Skip to content

Commit

Permalink
[asm] peep-hole optimization for optimising aggregate index operation (
Browse files Browse the repository at this point in the history
…FuelLabs#5270)

Index of aggregate accesses can use LW/SW's `imm` operand when the
offset is known statically and fits in 12 bits.

The peep-hole optimization only replaces the user LW/SW but does not
remove the computations itself. A DCE pass does that.

Closes FuelLabs#5228 

<details>
  <summary>Code size impact</summary>

test | before | after | %reduction
-- | -- | -- | --
should_pass/superabi_diamond | 164 | 164 | 0
should_pass/non_payable_implicit_zero_coins | 240 | 232 |
3.33333333333333
should_pass/supertraits_for_abis_ownable | 2868 | 2724 |
5.02092050209205
should_pass/superabi_supertrait_same_methods | 480 | 464 |
3.33333333333333
should_pass/forc/contract_dependencies/contract_b | 84 | 84 | 0
should_pass/forc/contract_dependencies/contract_c | 84 | 84 | 0
should_pass/forc/contract_dependencies/contract_a | 68 | 68 | 0
should_pass/forc/workspace_building | 28 | 28 | 0
should_pass/forc/dependency_package_field | 36 | 36 | 0
should_pass/forc/dependency_patching | 36 | 36 | 0
should_pass/forc/parent_pkg_manifest/contract_a | 84 | 84 | 0
should_pass/evm/evm_basic | 36 | 36 | 0
should_pass/language/basic_func_decl | 52 | 52 | 0
should_pass/language/integer_type_inference | 724 | 660 |
8.83977900552486
should_pass/language/const_decl_in_library | 92 | 92 | 0
should_pass/language/mutable_arrays_struct | 52 | 52 | 0
should_pass/language/unary_not_basic | 52 | 52 | 0
should_pass/language/name_resolution_inside_intrinsics | 84 | 84 | 0
should_pass/language/associated_const_trait_method | 36 | 36 | 0
should_pass/language/import_trailing_comma | 44 | 44 | 0
should_pass/language/struct_field_access | 52 | 52 | 0
should_pass/language/type_alias | 4844 | 4612 | 4.78943022295624
should_pass/language/mutable_arrays | 52 | 52 | 0
should_pass/language/prelude_access | 36 | 36 | 0
should_pass/language/trait_method_generic_qualified | 52 | 52 | 0
should_pass/language/generic_where_in_impl_self2 | 300 | 300 | 0
should_pass/language/array_generics | 76 | 76 | 0
should_pass/language/is_prime | 1156 | 1156 | 0
should_pass/language/out_of_order_decl | 60 | 60 | 0
should_pass/language/generic_tuple_trait | 380 | 380 | 0
should_pass/language/associated_const_impl_self | 36 | 36 | 0
should_pass/language/binary_and_hex_literals | 52 | 52 | 0
should_pass/language/chained_if_let | 180 | 164 | 8.88888888888889
should_pass/language/builtin_type_method_call | 52 | 52 | 0
should_pass/language/match_expressions_nested | 2372 | 1764 |
25.6323777403035
should_pass/language/raw_identifiers | 164 | 164 | 0
should_pass/language/struct_init_reorder | 92 | 84 | 8.69565217391304
should_pass/language/ref_mutable_fn_args_struct_assign | 52 | 52 | 0
should_pass/language/generic_enum | 52 | 52 | 0
should_pass/language/associated_type_fully_qualified | 36 | 36 | 0
should_pass/language/op_precedence | 36 | 36 | 0
should_pass/language/retd_struct | 168 | 168 | 0
should_pass/language/attributes_warnings | 36 | 36 | 0
should_pass/language/break_and_continue_block_ret | 44 | 44 | 0
should_pass/language/typeinfo_custom_callpath | 84 | 84 | 0
should_pass/language/associated_type_method | 36 | 36 | 0
should_pass/language/retd_small_array | 60 | 60 | 0
should_pass/language/many_stack_variables | 724 | 724 | 0
should_pass/language/name_resolution_after_monomorphization | 84 | 84 |
0
should_pass/language/multi_item_import | 36 | 36 | 0
should_pass/language/ref_mutable_fn_args_struct | 52 | 52 | 0
should_pass/language/inline_if_expr_const | 36 | 36 | 0
should_pass/language/contract_caller_as_ret | 84 | 84 | 0
should_pass/language/mutable_arrays_enum | 116 | 100 | 13.7931034482759
should_pass/language/ref_mutable_arrays | 52 | 52 | 0
should_pass/language/tuple_in_struct | 596 | 596 | 0
should_pass/language/doc_comments | 84 | 84 | 0
should_pass/language/unary_not_basic_2 | 52 | 52 | 0
should_pass/language/match_expressions_simple | 196 | 196 | 0
should_pass/language/gtf_intrinsic | 340 | 340 | 0
should_pass/language/modulo_uint_test | 340 | 340 | 0
should_pass/language/ret_string_in_struct | 80 | 80 | 0
should_pass/language/match_expressions_unreachable_catch_all_middle_arm
| 2116 | 1724 | 18.5255198487713
should_pass/language/smo_opcode | 128 | 128 | 0
should_pass/language/arg_demotion_inline | 372 | 348 | 6.45161290322581
should_pass/language/ret_small_string | 64 | 64 | 0
should_pass/language/match_expressions_rest | 2700 | 2684 |
0.592592592592593
should_pass/language/b256_bad_jumps | 36 | 36 | 0
should_pass/language/tuple_single_element | 84 | 84 | 0
should_pass/language/match_expressions_mismatched | 116 | 100 |
13.7931034482759
should_pass/language/basic_predicate | 52 | 52 | 0
should_pass/language/if_elseif_enum | 564 | 548 | 2.83687943262411
should_pass/language/associated_const_impl | 36 | 36 | 0
should_pass/language/associated_const_trait_const | 52 | 52 | 0
should_pass/language/implicit_return | 52 | 52 | 0
should_pass/language/generic_transpose | 820 | 740 | 9.75609756097561
should_pass/language/insert_element_reg_reuse | 3268 | 3220 |
1.468788249694
should_pass/language/where_clause_structs | 316 | 316 | 0
should_pass/language/enum_variant_imports | 284 | 268 | 5.63380281690141
should_pass/language/configurable_consts | 3764 | 3508 |
6.80127523910733
should_pass/language/match_expressions_with_self | 284 | 284 | 0
should_pass/language/where_clause_impls | 364 | 364 | 0
should_pass/language/enum_type_inference | 52 | 52 | 0
should_pass/language/implicit_casting | 52 | 52 | 0
should_pass/language/binop_intrinsics | 1140 | 1140 | 0
should_pass/language/abort_control_flow_good | 52 | 52 | 0
should_pass/language/match_expressions_structs | 156 | 156 | 0
should_pass/language/funcs_with_generic_types | 52 | 52 | 0
should_pass/language/typeinfo_custom_callpath2 | 84 | 84 | 0
should_pass/language/bool_and_or | 92 | 92 | 0
should_pass/language/eq_and_neq | 1316 | 1316 | 0
should_pass/language/const_decl_with_call_path | 316 | 316 | 0
should_pass/language/unit_type_variants | 60 | 60 | 0
should_pass/language/ops | 5884 | 5884 | 0
should_pass/language/far_jumps/many_blobs | 11640288 | 11640288 | 0
should_pass/language/far_jumps/single_blob | 1048656 | 1048656 | 0
should_pass/language/ref_mutable_fn_args_call | 44 | 44 | 0
should_pass/language/size_of | 292 | 292 | 0
should_pass/language/associated_type_ascription | 36 | 36 | 0
should_pass/language/zero_field_types | 52 | 52 | 0
should_pass/language/asm_without_return | 60 | 44 | 26.6666666666667
should_pass/language/str_slice | 128 | 120 | 6.25
should_pass/language/where_clause_functions | 1364 | 1364 | 0
should_pass/language/associated_const_impl_local_same_name | 36 | 36 | 0
should_pass/language/struct_destructuring | 204 | 204 | 0
should_pass/language/is_reference_type | 604 | 604 | 0
should_pass/language/impl_self_method | 52 | 52 | 0
should_pass/language/reassignment_operators | 292 | 292 | 0
should_pass/language/enum_if_let_large_type | 508 | 436 |
14.1732283464567
should_pass/language/match_expressions_enums | 10356 | 7924 |
23.4839706450367
should_pass/language/asm_expr_basic | 284 | 268 | 5.63380281690141
should_pass/language/same_const_name_lib | 28 | 28 | 0
should_pass/language/associated_const_abi | 36 | 36 | 0
should_pass/language/nested_structs | 1220 | 1220 | 0
should_pass/language/retd_b256 | 128 | 128 | 0
should_pass/language/same_const_name | 676 | 676 | 0
should_pass/language/blanket_trait | 52 | 52 | 0
should_pass/language/u256/u256_operators | 3644 | 3636 |
0.21953896816685
should_pass/language/u256/u256_abi | 156 | 156 | 0
should_pass/language/tuple_types | 52 | 52 | 0
should_pass/language/tuple_trait | 124 | 124 | 0
should_pass/language/associated_const_trait | 36 | 36 | 0
should_pass/language/predicate_while_dep | 84 | 84 | 0
should_pass/language/if_let_no_side_effects | 268 | 268 | 0
should_pass/language/generic_impl_self_where | 1284 | 1284 | 0
should_pass/language/deprecated | 28 | 28 | 0
should_pass/language/enum_if_let | 648 | 616 | 4.93827160493827
should_pass/language/main_returns_unit | 36 | 36 | 0
should_pass/language/tuple_indexing | 36 | 36 | 0
should_pass/language/mutable_arrays_nested | 36 | 36 | 0
should_pass/language/args_on_stack | 1172 | 1100 | 6.14334470989761
should_pass/language/match_expressions_empty_enums | 52 | 52 | 0
should_pass/language/associated_const_abi_default | 36 | 36 | 0
should_pass/language/shadowing/shadowed_glob_imports | 36 | 36 | 0
should_pass/language/eq_intrinsic | 652 | 652 | 0
should_pass/language/struct_field_reassignment | 36 | 36 | 0
should_pass/language/generic_structs | 52 | 52 | 0
should_pass/language/ref_mutable_arrays_inline | 52 | 52 | 0
should_pass/language/import_with_different_callpaths | 1700 | 1612 |
5.17647058823529
should_pass/language/main_args/main_args_ref_copy | 60 | 60 | 0
should_pass/language/main_args/main_args_copy | 52 | 52 | 0
should_pass/language/main_args/main_args_ref_ref | 60 | 60 | 0
should_pass/language/main_args/main_args_various_types | 588 | 556 |
5.4421768707483
should_pass/language/main_args/main_args_empty | 52 | 52 | 0
should_pass/language/main_args/main_args_ref | 52 | 52 | 0
should_pass/language/main_args/main_args_copy_copy | 52 | 52 | 0
should_pass/language/prelude_access2 | 36 | 36 | 0
should_pass/language/use_full_path_names | 36 | 36 | 0
should_pass/language/typeinfo_custom_callpath_with_import | 100 | 100 |
0
should_pass/language/retd_zero_len_array | 44 | 44 | 0
should_pass/language/where_clause_enums | 644 | 604 | 6.2111801242236
should_pass/language/generic_functions | 52 | 52 | 0
should_pass/language/b256_bitwise_ops | 5384 | 5384 | 0
should_pass/language/mutable_and_initd | 140 | 140 | 0
should_pass/language/enum_in_fn_decl | 132 | 132 | 0
should_pass/language/associated_const_abi_multiple | 36 | 36 | 0
should_pass/language/valid_impurity | 84 | 84 | 0
should_pass/language/nested_while_and_if | 172 | 172 | 0
should_pass/language/mutable_arrays_multiple_nested | 36 | 36 | 0
should_pass/language/where_clause_traits | 36 | 36 | 0
should_pass/language/supertraits | 3724 | 3724 | 0
should_pass/language/match_expressions_constants | 540 | 540 | 0
should_pass/language/impl_self_method_order | 52 | 52 | 0
should_pass/language/associated_const_impl_self_order | 36 | 36 | 0
should_pass/language/match_expressions_unreachable_last_arm | 3380 |
2900 | 14.2011834319527
should_pass/language/tuple_field_reassignment | 260 | 260 | 0
should_pass/language/enum_destructuring | 124 | 108 | 12.9032258064516
should_pass/language/revert_in_first_if_branch | 52 | 52 | 0
should_pass/language/logging | 544 | 528 | 2.94117647058823
should_pass/language/where_clause_methods | 1364 | 1364 | 0
should_pass/language/ref_mutable_fn_args_bool | 52 | 52 | 0
should_pass/language/associated_type_and_associated_const | 36 | 36 | 0
should_pass/language/diagnose_unknown_annotations | 116 | 116 | 0
should_pass/language/bitwise_not | 244 | 244 | 0
should_pass/language/generic_struct | 52 | 52 | 0
should_pass/language/match_expressions_unreachable_catch_all_last_arm |
2564 | 2076 | 19.0327613104524
should_pass/language/primitive_type_argument | 52 | 52 | 0
should_pass/language/fix_opcode_bug | 52 | 52 | 0
should_pass/language/trait_method_ascription_disambiguate | 52 | 52 | 0
should_pass/language/smo | 944 | 912 | 3.38983050847458
should_pass/language/import_method_from_other_file | 372 | 372 | 0
should_pass/language/aliased_imports | 52 | 52 | 0
should_pass/language/left_to_right_func_args_evaluation | 76 | 76 | 0
should_pass/language/mutable_arrays_swap | 52 | 52 | 0
should_pass/language/break_and_continue | 796 | 796 | 0
should_pass/language/memcpy | 228 | 228 | 0
should_pass/language/generic_type_inference | 2604 | 2396 |
7.98771121351767
should_pass/language/empty_method_initializer | 408 | 408 | 0
should_pass/language/const_inits | 2316 | 2252 | 2.76338514680484
should_pass/language/if_implicit_unit | 36 | 36 | 0
should_pass/language/enum_init_fn_call | 468 | 412 | 11.965811965812
should_pass/language/complex_cfg | 116 | 116 | 0
should_pass/language/use_absolute_path | 36 | 36 | 0
should_pass/language/enum_padding | 116 | 116 | 0
should_pass/language/method_type_args | 36 | 36 | 0
should_pass/language/method_on_empty_struct | 36 | 36 | 0
should_pass/language/const_decl | 52 | 52 | 0
should_pass/language/tuple_access | 192 | 184 | 4.16666666666667
should_pass/language/impure_ifs | 652 | 652 | 0
should_pass/language/ref_mutable_fn_args_u32 | 52 | 52 | 0
should_pass/language/associated_type_container | 916 | 868 |
5.24017467248908
should_pass/language/match_expressions_or | 31460 | 25796 |
18.0038143674507
should_pass/language/trait_import_with_star | 60 | 44 | 26.6666666666667
should_pass/language/generic_where_in_impl_self | 300 | 300 | 0
should_pass/language/match_expressions_explicit_rets | 52 | 52 | 0
should_pass/language/while_loops | 436 | 436 | 0
should_pass/language/generics_in_contract | 2048 | 1896 | 7.421875
should_pass/language/associated_const_trait_impl_method | 36 | 36 | 0
should_pass/language/contract_caller_dynamic_address | 144 | 136 |
5.55555555555556
should_pass/language/generic_result_method | 612 | 580 |
5.22875816993464
should_pass/language/local_impl_for_ord | 52 | 52 | 0
should_pass/language/match_expressions_inside_generic_functions | 612 |
612 | 0
should_pass/language/raw_ptr/vec_ret | 444 | 436 | 1.8018018018018
should_pass/language/raw_ptr/raw_ptr_ret | 180 | 180 | 0
should_pass/language/const_decl_and_use_in_library | 52 | 52 | 0
should_pass/language/predicate_while | 84 | 84 | 0
should_pass/language/generic_trait_constraints | 52 | 52 | 0
should_pass/language/test_attribute | 28 | 28 | 0
should_pass/language/numeric_constants | 436 | 436 | 0
should_pass/language/generic_impl_self | 1820 | 1756 | 3.51648351648352
should_pass/language/generic_inside_generic | 164 | 132 |
19.5121951219512
should_pass/language/match_expressions | 804 | 772 | 3.98009950248756
should_pass/language/associated_type_parameter | 36 | 36 | 0
should_pass/language/associated_const_trait_default | 52 | 52 | 0
should_pass/language/generic_traits | 772 | 772 | 0
should_pass/language/self_impl_reassignment | 972 | 868 |
10.6995884773663
should_pass/language/associated_type_iterator | 1140 | 1092 |
4.21052631578947
should_pass/language/b256_ops | 2936 | 2776 | 5.44959128065395
should_pass/language/associated_const_impl_multiple | 36 | 36 | 0
should_pass/language/multi_impl_self | 52 | 52 | 0
should_pass/language/array_basics | 444 | 428 | 3.6036036036036
should_pass/language/tuple_desugaring | 100 | 100 | 0
should_pass/language/non_literal_const_decl | 52 | 52 | 0
should_pass/language/supertraits_with_trait_methods | 116 | 116 | 0
should_pass/language/redundant_return | 36 | 36 | 0
should_pass/language/nested_struct_destructuring | 36 | 36 | 0
should_pass/language/test_multiple_attributes | 28 | 28 | 0
should_pass/language/diverging_exprs | 1980 | 1948 | 1.61616161616162
should_pass/language/match_expressions_unreachable_middle_arm | 3948 |
3308 | 16.2107396149949
should_pass/language/trait_method_qualified | 292 | 292 | 0
should_pass/language/new_allocator_test | 844 | 844 | 0
should_pass/stdlib/assert_eq_u256_revert | 212 | 188 | 11.3207547169811
should_pass/stdlib/sha256 | 960 | 952 | 0.833333333333333
should_pass/stdlib/u256_div_test | 14148 | 13564 | 4.12779191405146
should_pass/stdlib/result | 8224 | 7032 | 14.4941634241245
should_pass/stdlib/u128_mul_test | 804 | 756 | 5.97014925373134
should_pass/stdlib/require | 52 | 52 | 0
should_pass/stdlib/address_test | 2056 | 2056 | 0
should_pass/stdlib/storage_vec_insert | 5056 | 4720 | 6.64556962025316
should_pass/stdlib/eq_custom_type | 492 | 452 | 8.13008130081301
should_pass/stdlib/alloc | 788 | 788 | 0
should_pass/stdlib/u256_ops_test | 14004 | 13420 | 4.17023707512139
should_pass/stdlib/if_type_revert | 36 | 36 | 0
should_pass/stdlib/u256_test | 2692 | 2508 | 6.83506686478455
should_pass/stdlib/b512_test | 2784 | 2784 | 0
should_pass/stdlib/assert_eq_revert | 68 | 68 | 0
should_pass/stdlib/option | 31712 | 28504 | 10.1160443995964
should_pass/stdlib/exponentiation_test | 3084 | 3084 | 0
should_pass/stdlib/vec | 107176 | 102904 | 3.985967007539
should_pass/stdlib/vec_swap | 19808 | 18704 | 5.5735056542811
should_pass/stdlib/assert_test | 316 | 316 | 0
should_pass/stdlib/raw_slice | 476 | 460 | 3.36134453781513
should_pass/stdlib/intrinsics | 700 | 700 | 0
should_pass/stdlib/ge_test | 388 | 388 | 0
should_pass/stdlib/generic_empty_struct_with_constraint | 36 | 36 | 0
should_pass/stdlib/u128_test | 4340 | 4196 | 3.31797235023041
should_pass/stdlib/contract_id_test | 288 | 288 | 0
should_pass/stdlib/contract_id_type | 284 | 284 | 0
should_pass/stdlib/chess | 1820 | 1820 | 0
should_pass/stdlib/raw_ptr | 2388 | 2364 | 1.00502512562814
should_pass/stdlib/u128_root_test | 12684 | 12468 | 1.70293282876064
should_pass/stdlib/logarithmic_test | 1716 | 1716 | 0
should_pass/stdlib/assert_eq | 2756 | 2668 | 3.19303338171263
should_pass/stdlib/block_height | 92 | 92 | 0
should_pass/stdlib/u256_mul_test | 16932 | 15964 | 5.71698558941649
should_pass/stdlib/eq_generic | 36 | 36 | 0
should_pass/stdlib/u128_div_test | 2044 | 2012 | 1.56555772994129
should_pass/stdlib/u128_log_test | 11452 | 11356 | 0.8382815228781
should_pass/stdlib/identity_eq | 6292 | 5908 | 6.10298792116974
should_pass/stdlib/b512_struct_alignment | 304 | 304 | 0
should_pass/dca/impl_trait_single | 36 | 36 | 0
should_pass/dca/multiple_fns_same_name | 36 | 36 | 0
should_pass/dca/trait_method | 36 | 36 | 0
should_pass/dca/unused_trait | 36 | 36 | 0
should_pass/dca/trait_method_neq | 132 | 132 | 0
should_pass/dca/alias_lib | 100 | 92 | 8
should_pass/dca/trait_method_lib | 28 | 28 | 0
should_pass/dca/multiple_enums_same_name | 36 | 36 | 0
should_pass/dca/contract/unused_struct_field_array | 100 | 100 | 0
should_pass/dca/contract/unused_struct_field_enum | 92 | 92 | 0
should_pass/dca/contract/unused_struct_field | 76 | 76 | 0
should_pass/dca/contract/abi_fn_params | 116 | 116 | 0
should_pass/dca/contract/superabi_contract_calls | 204 | 188 |
7.84313725490196
should_pass/dca/contract/unused_struct_field_tuple | 76 | 76 | 0
should_pass/dca/unused_struct | 36 | 36 | 0
should_pass/dca/unused_free_fn | 36 | 36 | 0
should_pass/dca/impl_self | 36 | 36 | 0
should_pass/dca/unused_variable | 36 | 36 | 0
should_pass/dca/all_paths_return | 36 | 36 | 0
should_pass/dca/allow_dead_code | 36 | 36 | 0
should_pass/dca/log_stdlib | 52 | 52 | 0
should_pass/dca/impl_self_alias2 | 36 | 36 | 0
should_pass/dca/struct_field_no_warning | 44 | 44 | 0
should_pass/dca/log_intrinsic | 52 | 52 | 0
should_pass/dca/unused_enum | 36 | 36 | 0
should_pass/dca/constant_struct | 52 | 52 | 0
should_pass/dca/impl_unused_fn | 52 | 52 | 0
should_pass/dca/library/fn_params_free | 28 | 28 | 0
should_pass/dca/library/fn_params_impl | 28 | 28 | 0
should_pass/dca/library/unused_priv_free_fn | 28 | 28 | 0
should_pass/dca/library/unused_pub_free_fn | 28 | 28 | 0
should_pass/dca/library/fn_params_trait | 28 | 28 | 0
should_pass/dca/unused_variable_in_free_fn | 36 | 36 | 0
should_pass/dca/generic_fn_trait_contraint | 36 | 36 | 0
should_pass/dca/func_param | 36 | 36 | 0
should_pass/dca/alias_type_ascription_generic | 36 | 36 | 0
should_pass/dca/alias_unused | 36 | 36 | 0
should_pass/dca/impl_trait_multiple | 36 | 36 | 0
should_pass/dca/impl_self_alias | 36 | 36 | 0
should_pass/dca/alias_type_ascription | 36 | 36 | 0
should_pass/dca/constant_decl_expr | 52 | 52 | 0
should_pass/dca/constant_while | 36 | 36 | 0
should_pass/dca/unused_fields | 36 | 36 | 0
should_pass/dca/revert | 36 | 36 | 0
should_pass/superabi_diamond_impl | 164 | 164 | 0
should_pass/static_analysis/cei_pattern_violation_storage_var_read | 900
| 828 | 8
should_pass/static_analysis/cei_pattern_violation_in_intrinsic_call |
664 | 616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_tuple | 664 | 616 |
7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_asm_block | 240 |
232 | 3.33333333333333
should_pass/static_analysis/cei_pattern_violation_in_while_loop-4 | 664
| 616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_asm_block_tr | 332
| 324 | 2.40963855421687
should_pass/static_analysis/cei_pattern_violation_smo_intrinsic | 304 |
296 | 2.63157894736842
should_pass/static_analysis/cei_pattern_violation_more_complex_logic |
12472 | 11536 | 7.50481077613855
should_pass/static_analysis/cei_pattern_violation_in_struct | 664 | 616
| 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_asm_block_read |
224 | 216 | 3.57142857142857
should_pass/static_analysis/cei_pattern_violation_in_while_loop-2 | 664
| 616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_while_loop-1 | 664
| 616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_while_loop-3 | 664
| 616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_func_app-1 | 664 |
616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_func_app-2 | 664 |
616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation | 656 | 616 |
6.09756097560976
should_pass/static_analysis/cei_pattern_violation_in_asm_block_tro | 860
| 852 | 0.930232558139535
should_pass/static_analysis/cei_pattern_violation_in_func_app-3 | 664 |
616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_if_statement-2 |
664 | 616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_asm_block_bal | 212
| 196 | 7.54716981132076
should_pass/static_analysis/storage_annotations_unused_read | 68 | 68 |
0

should_pass/static_analysis/cei_pattern_violation_in_codeblocks_other_than_in_functions
| 664 | 616 | 7.2289156626506
should_pass/static_analysis/cei_pattern_violation_in_asm_block_smo | 220
| 212 | 3.63636363636364
should_pass/static_analysis/cei_pattern_violation_storage_struct_read |
916 | 860 | 6.11353711790393
should_pass/static_analysis/cei_pattern_violation_storage_var_update |
820 | 764 | 6.82926829268293

should_pass/static_analysis/cei_pattern_violation_in_standalone_function
| 656 | 616 | 6.09756097560976
should_pass/static_analysis/storage_annotations_unused_read_and_write |
68 | 68 | 0
should_pass/static_analysis/storage_annotations_unused_write | 68 | 68 |
0
should_pass/static_analysis/cei_pattern_violation_in_if_statement-1 |
688 | 640 | 6.97674418604651
should_pass/static_analysis/cei_pattern_violation_storage_map_and_vec |
5068 | 4684 | 7.57695343330703
should_pass/static_analysis/cei_pattern_violation_in_match_statement-1 |
760 | 720 | 5.26315789473684
should_pass/supertraits_for_abis_diamond | 68 | 68 | 0
should_pass/test_abis/abi_impl_methods_in_json_abi | 100 | 100 | 0
should_pass/test_abis/abi_impl_method_duplicate ... |   |   | #DIV/0!
should_pass/test_abis/abi_impl_methods_callable | 260 | 252 |
3.07692307692308
should_pass/superabi | 100 | 100 | 0
should_pass/non_payable_zero_coins_let_binding | 240 | 232 |
3.33333333333333
should_pass/blanket_impl_u16 | 52 | 52 | 0
should_pass/multiple_supertraits_for_abis | 100 | 100 | 0
should_pass/unit_tests/contract_with_nested_libs | 164 | 164 | 0
should_pass/unit_tests/script_with_nested_libs | 132 | 132 | 0
should_pass/unit_tests/should_revert | 68 | 68 | 0
should_pass/unit_tests/predicate_multi_test | 220 | 220 | 0
should_pass/unit_tests/lib_single_test | 36 | 36 | 0
should_pass/unit_tests/regalloc_spill | 412 | 412 | 0
should_pass/unit_tests/contract_multi_test | 380 | 364 |
4.21052631578947
should_pass/unit_tests/script_multi_test | 136 | 128 | 5.88235294117647
should_pass/unit_tests/nested_libs | 124 | 124 | 0
should_pass/unit_tests/workspace_test | 136 | 128 | 5.88235294117647
should_pass/unit_tests/contract-multi-contract-calls | 68 | 68 | 0
should_pass/unit_tests/script-contract-calls | 68 | 68 | 0
should_pass/unit_tests/stack_indexing_overflow | 3804 | 3748 |
1.47213459516299
should_pass/unit_tests/predicate_with_nested_libs | 84 | 84 | 0
should_pass/unit_tests/lib_multi_test | 116 | 116 | 0
should_pass/supertraits_via_self | 36 | 36 | 0
should_pass/test_contracts/storage_configurable | 84 | 84 | 0
should_pass/test_contracts/storage_enum_contract | 44300 | 40644 |
8.25282167042889
should_pass/test_contracts/context_testing_contract | 388 | 388 | 0
should_pass/test_contracts/contract_with_type_aliases | 172 | 172 | 0
should_pass/test_contracts/basic_storage | 31016 | 29040 |
6.37090533917978
should_pass/test_contracts/storage_access_contract | 21260 | 19708 |
7.30009407337723
should_pass/test_contracts/auth_testing_contract | 76 | 76 | 0
should_pass/test_contracts/nested_struct_args_contract | 100 | 100 | 0
should_pass/test_contracts/abi_with_tuples_contract | 124 | 116 |
6.45161290322581
should_pass/test_contracts/test_fuel_coin_contract | 276 | 276 | 0
should_pass/test_contracts/array_of_structs_contract | 196 | 196 | 0
should_pass/test_contracts/return_struct | 1212 | 1108 |
8.58085808580858
should_pass/test_contracts/abi_with_generic_types | 192 | 160 |
16.6666666666667
should_pass/test_contracts/balance_test_contract | 84 | 84 | 0
should_pass/test_contracts/multiple_impl | 92 | 92 | 0
should_pass/test_contracts/abi_with_same_name_types | 112 | 96 |
14.2857142857143
should_pass/test_contracts/issue_1512_repro | 1284 | 1196 |
6.85358255451713
should_pass/test_contracts/increment_contract | 1676 | 1532 |
8.59188544152745
should_pass/superabi_contract_calls | 480 | 464 | 3.33333333333333
should_pass/conditional_compilation/run | 52 | 52 | 0
should_pass/empty_fields_in_storage_struct | 16112 | 14864 |
7.74577954319762
should_pass/payable_non_zero_coins | 196 | 188 | 4.08163265306122
should_pass/supertraits_for_abis | 100 | 100 | 0
should_pass/blanket_impl | 52 | 52 | 0
</details>

---------

Co-authored-by: IGI-111 <[email protected]>
Co-authored-by: Joshua Batty <[email protected]>
Co-authored-by: Igor Rončević <[email protected]>
  • Loading branch information
4 people authored Dec 6, 2023
1 parent fc17c39 commit f60d637
Show file tree
Hide file tree
Showing 26 changed files with 761 additions and 137 deletions.
8 changes: 6 additions & 2 deletions sway-core/src/asm_generation/fuel/abstract_instruction_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use std::{collections::HashSet, fmt};

use either::Either;

use super::data_section::DataSection;

/// An [AbstractInstructionSet] is a set of instructions that use entirely virtual registers
/// and excessive moves, with the intention of later optimizing it.
#[derive(Clone)]
Expand All @@ -23,8 +25,10 @@ pub struct AbstractInstructionSet {
}

impl AbstractInstructionSet {
pub(crate) fn optimize(self) -> AbstractInstructionSet {
self.remove_sequential_jumps()
pub(crate) fn optimize(self, data_section: &DataSection) -> AbstractInstructionSet {
self.const_indexing_aggregates_function(data_section)
.dce()
.remove_sequential_jumps()
.remove_redundant_moves()
.remove_unused_ops()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ impl AllocatedAbstractInstructionSet {
match op.opcode {
Either::Right(Label(_)) => 0,

// A special case for LWDataId which may be 1 or 2 ops, depending on the source size.
// A special case for LoadDataId which may be 1 or 2 ops, depending on the source size.
Either::Left(AllocatedOpcode::LoadDataId(_, ref data_id)) => {
let has_copy_type = data_section.has_copy_type(data_id).expect(
"Internal miscalculation in data section -- \
Expand Down
110 changes: 110 additions & 0 deletions sway-core/src/asm_generation/fuel/analyses.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use std::collections::{BTreeSet, HashMap};

use either::Either;
use rustc_hash::FxHashSet;

use crate::asm_lang::{ControlFlowOp, Label, Op, VirtualRegister};

/// Given a list of instructions `ops` of a program, do liveness analysis for the full program.
///
/// A virtual registers is live at some point in the program if it has previously been defined by
/// an instruction and will be used by an instruction in the future.
///
/// The analysis function below assumes that it is possible that a virtual register is assigned
/// more than once. That is, it doesn't assume that the intermediate assembly is in SSA form.
///
/// Two tables are generated: `live_in` and `live_out`. Each row in the tables corresponds to an
/// instruction in the program.
/// * A virtual register is in the `live_out` table for a given instruction if it is live on any
/// of that node's out-edges
/// * A virtual register is in the `live_in` table for a given instruction if it is live on any
/// of that node's in-edges
///
///
/// Algorithm:
/// ===============================================================================================
/// for each instruction op:
/// live_in(op) = {}
/// live_out(op) = {}
/// def(op) = list of virtual registers defined by op
/// use(op) = list of virtual registers used by op
///
/// repeat
/// for each instruction op (traversed in reverse topological order of the CFG)
/// prev_live_in(op) = live_in(op)
/// prev_live_out(op) = live_out(op)
/// live_out(op) = live_in(s_1) UNION live_in(s_2) UNION live_in(s_3) UNION ...
/// where s_1, s_2, s_3, ... are all the successors of op in the CFG.
/// live_in(op) = use(op) UNION (live_out(op) - def(op))
/// until prev_live_in(op) = live_in(op)
/// AND prev_live_out(op) = live_out(op)
/// ===============================================================================================
///
/// If `ignore_constant_regs == true` then we only look at registers that have the enum variant
/// VirtualRegister::Virtual(_). All other registers (i.e. ones with the
/// VirtualRegister::Constant(_) variant) are assumed to be live throughout the full program.
///
/// This function finally returns `live_out` because it has all the liveness information needed.
/// `live_in` is computed because it is needed to compute `live_out` iteratively.
///
pub(crate) fn liveness_analysis(
ops: &[Op],
ignore_constant_regs: bool,
) -> Vec<BTreeSet<VirtualRegister>> {
// Vectors representing maps that will represent the live_in and live_out tables. Each entry
// corresponds to an instruction in `ops`.
let mut live_in: Vec<FxHashSet<VirtualRegister>> = vec![FxHashSet::default(); ops.len()];
let mut live_out: Vec<BTreeSet<VirtualRegister>> = vec![BTreeSet::default(); ops.len()];
let mut label_to_index: HashMap<Label, usize> = HashMap::new();

// Keep track of a map between jump labels and op indices. Useful to compute op successors.
for (idx, op) in ops.iter().enumerate() {
if let Either::Right(ControlFlowOp::Label(op_label)) = op.opcode {
label_to_index.insert(op_label, idx);
}
}

let mut modified = true;
while modified {
modified = false;
// Iterate in reverse topological order of the CFG (which is basically the same as the
// reverse order of `ops`. This makes the outer `while` loop converge faster.
for (ix, op) in ops.iter().rev().enumerate() {
let mut local_modified = false;
let rev_ix = ops.len() - ix - 1;

// Get use and def vectors without any of the Constant registers
let mut op_use = op.use_registers();
let mut op_def = op.def_registers();
if ignore_constant_regs {
op_use.retain(|&reg| reg.is_virtual());
op_def.retain(|&reg| reg.is_virtual());
}

// Compute live_out(op) = live_in(s_1) UNION live_in(s_2) UNION ..., where s1, s_2, ...
// are successors of op
for s in &op.successors(rev_ix, ops, &label_to_index) {
for l in live_in[*s].iter() {
local_modified |= live_out[rev_ix].insert(l.clone());
}
}

// Compute live_in(op) = use(op) UNION (live_out(op) - def(op))
// Add use(op)
for u in op_use {
local_modified |= live_in[rev_ix].insert(u.clone());
}
// Add live_out(op) - def(op)
for l in live_out[rev_ix].iter() {
if !op_def.contains(&l) {
local_modified |= live_in[rev_ix].insert(l.clone());
}
}

// Did anything change in this iteration?
modified |= local_modified;
}
}

live_out
}
11 changes: 11 additions & 0 deletions sway-core/src/asm_generation/fuel/data_section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,17 @@ impl DataSection {
}
}
}

// If the stored data is Datum::Word, return the inner value.
pub(crate) fn get_data_word(&self, data_id: &DataId) -> Option<u64> {
self.value_pairs.get(data_id.0 as usize).and_then(|entry| {
if let Datum::Word(w) = entry.value {
Some(w)
} else {
None
}
})
}
}

impl fmt::Display for DataSection {
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/asm_generation/fuel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ pub(super) mod checks;
pub(super) mod fuel_asm_builder;
pub(super) mod register_sequencer;

mod analyses;
mod functions;
mod optimizations;
Loading

0 comments on commit f60d637

Please sign in to comment.