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.
This commit is contained in:
parent
487c9df602
commit
772fcf4769
3 changed files with 138 additions and 36 deletions
|
@ -1162,9 +1162,6 @@ package body Exp_Ch4 is
|
|||
|
||||
Comp : RE_Id;
|
||||
|
||||
Byte_Addressable : constant Boolean := System_Storage_Unit = Byte'Size;
|
||||
-- True for byte addressable target
|
||||
|
||||
function Length_Less_Than_4 (Opnd : Node_Id) return Boolean;
|
||||
-- Returns True if the length of the given operand is known to be less
|
||||
-- than 4. Returns False if this length is known to be four or greater
|
||||
|
@ -1198,11 +1195,12 @@ package body Exp_Ch4 is
|
|||
-- Start of processing for Expand_Array_Comparison
|
||||
|
||||
begin
|
||||
-- Deal first with unpacked case, where we can call a runtime routine
|
||||
-- except that we avoid this for targets for which are not addressable
|
||||
-- by bytes.
|
||||
-- Deal first with unpacked case, where we can call a runtime routine,
|
||||
-- except if the component type is a byte (unsigned) where we can use
|
||||
-- a byte-wise comparison if supported on the target (this is disabled
|
||||
-- for now in Unnest_Subprogram_Mode for LLVM).
|
||||
|
||||
if not Is_Bit_Packed_Array (Typ1) and then Byte_Addressable then
|
||||
if not Is_Bit_Packed_Array (Typ1) then
|
||||
-- The call we generate is:
|
||||
|
||||
-- Compare_Array_xn[_Unaligned]
|
||||
|
@ -1214,9 +1212,18 @@ package body Exp_Ch4 is
|
|||
-- <op> is the standard comparison operator
|
||||
|
||||
if Component_Size (Typ1) = 8 then
|
||||
if Length_Less_Than_4 (Op1)
|
||||
or else
|
||||
Length_Less_Than_4 (Op2)
|
||||
if Is_Unsigned_Type (Ctyp)
|
||||
and then not Is_Possibly_Unaligned_Object (Op1)
|
||||
and then not Is_Possibly_Unaligned_Slice (Op1)
|
||||
and then not Is_Possibly_Unaligned_Object (Op2)
|
||||
and then not Is_Possibly_Unaligned_Slice (Op2)
|
||||
and then Support_Composite_Compare_On_Target
|
||||
and then not Unnest_Subprogram_Mode
|
||||
then
|
||||
return;
|
||||
|
||||
elsif Length_Less_Than_4 (Op1)
|
||||
or else Length_Less_Than_4 (Op2)
|
||||
then
|
||||
if Is_Unsigned_Type (Ctyp) then
|
||||
Comp := RE_Compare_Array_U8_Unaligned;
|
||||
|
@ -1261,11 +1268,10 @@ package body Exp_Ch4 is
|
|||
end if;
|
||||
end if;
|
||||
|
||||
-- Expand to a call only if the runtime function is available,
|
||||
-- otherwise fall back to inline code.
|
||||
|
||||
if RTE_Available (Comp) then
|
||||
|
||||
-- Expand to a call only if the runtime function is available,
|
||||
-- otherwise fall back to inline code.
|
||||
|
||||
Remove_Side_Effects (Op1, Name_Req => True);
|
||||
Remove_Side_Effects (Op2, Name_Req => True);
|
||||
|
||||
|
@ -1292,8 +1298,7 @@ package body Exp_Ch4 is
|
|||
Attribute_Name => Name_Length)));
|
||||
|
||||
Zero : constant Node_Id :=
|
||||
Make_Integer_Literal (Loc,
|
||||
Intval => Uint_0);
|
||||
Make_Integer_Literal (Loc, Intval => Uint_0);
|
||||
|
||||
Comp_Op : Node_Id;
|
||||
|
||||
|
@ -8230,8 +8235,8 @@ package body Exp_Ch4 is
|
|||
then
|
||||
Expand_Packed_Eq (N);
|
||||
|
||||
-- Where the component type is elementary we can use a block bit
|
||||
-- comparison (if supported on the target) exception in the case
|
||||
-- When the component type is elementary, we can use a byte-wise
|
||||
-- comparison if supported on the target, except in the cases
|
||||
-- of floating-point (negative zero issues require element by
|
||||
-- element comparison), and full access types (where we must be sure
|
||||
-- to load elements independently) and possibly unaligned arrays.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -359,11 +359,12 @@ package Targparm is
|
|||
-- the flag is set False, and composite assignments are not allowed.
|
||||
|
||||
Support_Composite_Compare_On_Target : Boolean := True;
|
||||
-- If this flag is True, then the back end supports bit-wise comparison
|
||||
-- of composite objects for equality, either generating inline code or
|
||||
-- calling appropriate (and available) run-time routines. If this flag
|
||||
-- is False, then the back end does not provide this support, and the
|
||||
-- front end uses component by component comparison for composites.
|
||||
-- If this flag is True, then the back end supports byte-wise comparison
|
||||
-- of arrays for equality operations and lexicographic comparison of 1-
|
||||
-- dimensional arrays of bytes for ordering operations, either by means
|
||||
-- of generating inline code or calling appropriate routines like memcmp.
|
||||
-- If this flag is False, then the back end does not provide this support,
|
||||
-- and the front end uses component by component comparison for arrays.
|
||||
|
||||
Support_Long_Shifts_On_Target : Boolean := True;
|
||||
-- If True, the back end supports 64-bit shift operations. If False, then
|
||||
|
|
Loading…
Add table
Reference in a new issue