diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2024-06-17 09:54:47 +0200 |
---|---|---|
committer | Marc Poulhiès <dkm@gcc.gnu.org> | 2024-07-02 15:20:34 +0200 |
commit | 772fcf4769a4d4e5546039c0174662df1bc86fa4 (patch) | |
tree | 5f8b0ea81fff0f8d098bc0aa940342e6dffe9db0 /gcc/ada/gcc-interface | |
parent | 487c9df60263baf92c121b986ce19259a8c769d1 (diff) | |
download | gcc-772fcf4769a4d4e5546039c0174662df1bc86fa4.zip gcc-772fcf4769a4d4e5546039c0174662df1bc86fa4.tar.gz gcc-772fcf4769a4d4e5546039c0174662df1bc86fa4.tar.bz2 |
ada: Call memcmp instead of Compare_Array_Unsigned_8 and...
... implement support for ordering comparisons of discrete array types.
This extends the Support_Composite_Compare_On_Target feature to ordering
comparisons of discrete array types as specified by RM 4.5.2(26/3), when
the component type is a byte (unsigned).
Implement support for ordering comparisons of discrete array types
with a two-pronged approach: for types with a size known at compile time,
this lets the gimplifier generate the call to memcmp (or else an optimize
version of it); otherwise, this directly generates the call to memcmp.
gcc/ada/
* exp_ch4.adb (Expand_Array_Comparison): Remove the obsolete byte
addressibility test. If Support_Composite_Compare_On_Target is true,
immediately return for a component size of 8, an unsigned component
type and aligned operands. Disable when Unnest_Subprogram_Mode is
true (for LLVM).
(Expand_N_Op_Eq): Adjust comment.
* targparm.ads (Support_Composite_Compare_On_Target): Replace bit by
byte in description and document support for ordering comparisons.
* gcc-interface/utils2.cc (compare_arrays): Rename into...
(compare_arrays_for_equality): ...this. Remove redundant lines.
(compare_arrays_for_ordering): New function.
(build_binary_op) <comparisons>: Call compare_arrays_for_ordering
to implement ordering comparisons for arrays.
Diffstat (limited to 'gcc/ada/gcc-interface')
-rw-r--r-- | gcc/ada/gcc-interface/utils2.cc | 122 |
1 files changed, 109 insertions, 13 deletions
diff --git a/gcc/ada/gcc-interface/utils2.cc b/gcc/ada/gcc-interface/utils2.cc index d101d77..0d7e03e 100644 --- a/gcc/ada/gcc-interface/utils2.cc +++ b/gcc/ada/gcc-interface/utils2.cc @@ -283,7 +283,7 @@ find_common_type (tree t1, tree t2) tests in as efficient a manner as possible. */ static tree -compare_arrays (location_t loc, tree result_type, tree a1, tree a2) +compare_arrays_for_equality (location_t loc, tree result_type, tree a1, tree a2) { tree result = convert (result_type, boolean_true_node); tree a1_is_null = convert (result_type, boolean_false_node); @@ -357,8 +357,6 @@ compare_arrays (location_t loc, tree result_type, tree a1, tree a2) ub1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (ub1, a1); comparison = fold_build2_loc (loc, LT_EXPR, result_type, ub1, lb1); - if (EXPR_P (comparison)) - SET_EXPR_LOCATION (comparison, loc); this_a1_is_null = comparison; this_a2_is_null = convert (result_type, boolean_true_node); @@ -380,9 +378,6 @@ compare_arrays (location_t loc, tree result_type, tree a1, tree a2) ub1, lb1), build_binary_op (MINUS_EXPR, base_type, ub2, lb2)); - if (EXPR_P (comparison)) - SET_EXPR_LOCATION (comparison, loc); - this_a1_is_null = fold_build2_loc (loc, LT_EXPR, result_type, ub1, lb1); @@ -397,8 +392,6 @@ compare_arrays (location_t loc, tree result_type, tree a1, tree a2) comparison = fold_build2_loc (loc, EQ_EXPR, result_type, length1, length2); - if (EXPR_P (comparison)) - SET_EXPR_LOCATION (comparison, loc); lb1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (lb1, a1); ub1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (ub1, a1); @@ -464,6 +457,89 @@ compare_arrays (location_t loc, tree result_type, tree a1, tree a2) return result; } +/* Return an expression tree representing an ordering comparison of A1 and A2, + two objects of type ARRAY_TYPE. The result should be of type RESULT_TYPE. + + A1 is less than A2 according to the following alternative: + - when A1's length is less than A2'length: if every element of A1 is equal + to its counterpart in A2 or the first differing is lesser in A1 than A2, + - otherwise: if not every element of A2 is equal to its counterpart in A1 + and the first differing is lesser in A1 than A2. + + The other 3 ordering comparisons can be easily deduced from this one. */ + +static tree +compare_arrays_for_ordering (location_t loc, tree result_type, tree a1, tree a2) +{ + const bool a1_side_effects_p = TREE_SIDE_EFFECTS (a1); + const bool a2_side_effects_p = TREE_SIDE_EFFECTS (a2); + tree t1 = TREE_TYPE (a1); + tree t2 = TREE_TYPE (a2); + tree dom1 = TYPE_DOMAIN (t1); + tree dom2 = TYPE_DOMAIN (t2); + tree length1 = size_binop (PLUS_EXPR, + size_binop (MINUS_EXPR, + TYPE_MAX_VALUE (dom1), + TYPE_MIN_VALUE (dom1)), + size_one_node); + tree length2 = size_binop (PLUS_EXPR, + size_binop (MINUS_EXPR, + TYPE_MAX_VALUE (dom2), + TYPE_MIN_VALUE (dom2)), + size_one_node); + tree addr1, addr2, fndecl, result; + + /* If the lengths are known at compile time, fold the alternative and let the + gimplifier optimize the case of power-of-two lengths. */ + if (TREE_CODE (length1) == INTEGER_CST && TREE_CODE (length2) == INTEGER_CST) + return tree_int_cst_compare (length1, length2) < 0 + ? fold_build2_loc (loc, LE_EXPR, result_type, a1, convert (t1, a2)) + : fold_build2_loc (loc, LT_EXPR, result_type, convert (t2, a1), a2); + + /* If the operands have side-effects, they need to be evaluated only once + in spite of the multiple references in the comparison. */ + if (a1_side_effects_p) + a1 = gnat_protect_expr (a1); + + if (a2_side_effects_p) + a2 = gnat_protect_expr (a2); + + length1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (length1, a1); + length2 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (length2, a2); + + /* If the lengths are not known at compile time, call memcmp directly with + the actual lengths since a1 and a2 may have the same nominal subtype. */ + addr1 = build_fold_addr_expr_loc (loc, a1); + addr2 = build_fold_addr_expr_loc (loc, a2); + fndecl = builtin_decl_implicit (BUILT_IN_MEMCMP); + + result + = fold_build3_loc (loc, COND_EXPR, result_type, + fold_build2_loc (loc, LT_EXPR, boolean_type_node, + length1, length2), + fold_build2_loc (loc, LE_EXPR, result_type, + build_call_expr_loc (loc, fndecl, 3, + addr1, addr2, + length1), + integer_zero_node), + fold_build2_loc (loc, LT_EXPR, result_type, + build_call_expr_loc (loc, fndecl, 3, + addr1, addr2, + length2), + integer_zero_node)); + + /* If the operands have side-effects, they need to be evaluated before + doing the tests above since the place they otherwise would end up + being evaluated at run time could be wrong. */ + if (a1_side_effects_p) + result = build2 (COMPOUND_EXPR, result_type, a1, result); + + if (a2_side_effects_p) + result = build2 (COMPOUND_EXPR, result_type, a2, result); + + return result; +} + /* Return an expression tree representing an equality comparison of P1 and P2, two objects of fat pointer type. The result should be of type RESULT_TYPE. @@ -1176,12 +1252,32 @@ build_binary_op (enum tree_code op_code, tree result_type, || (TREE_CODE (right_type) == INTEGER_TYPE && TYPE_HAS_ACTUAL_BOUNDS_P (right_type)))) { - result = compare_arrays (input_location, - result_type, left_operand, right_operand); - if (op_code == NE_EXPR) - result = invert_truthvalue_loc (EXPR_LOCATION (result), result); + if (op_code == EQ_EXPR || op_code == NE_EXPR) + { + result + = compare_arrays_for_equality (input_location, result_type, + left_operand, right_operand); + if (op_code == NE_EXPR) + result = invert_truthvalue_loc (input_location, result); + } + else - gcc_assert (op_code == EQ_EXPR); + { + /* Swap the operands to canonicalize to LT_EXPR or GE_EXPR. */ + if (op_code == GT_EXPR || op_code == LE_EXPR) + result + = compare_arrays_for_ordering (input_location, result_type, + right_operand, left_operand); + + else + result + = compare_arrays_for_ordering (input_location, result_type, + left_operand, right_operand); + + /* GE_EXPR is (not LT_EXPR) for discrete array types. */ + if (op_code == GE_EXPR || op_code == LE_EXPR) + result = invert_truthvalue_loc (input_location, result); + } return result; } |