Hi,

the Ada compiler now defers to the gimplifier for ordering comparisons of 
arrays of bytes (Ada parlance for <, >, <= and >=) because the gimplifier in 
turn defers to memcmp for them, which implements the required semantics.

However the gimplifier has a special processing for aggregate types whose mode 
is not BLKmode and this processing deviates from the memcmp semantics when the 
target is little-endian.

Tested on x86-64/Linux, OK for the mainline?


2024-07-08  Eric Botcazou  <ebotca...@adacore.com>

        * gimplify.cc (gimplify_scalar_mode_aggregate_compare): Add support
        for ordering comparisons.


2024-07-08  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/array42.adb,/gnat.dg/array42_pkg.ads: New test.

-- 
Eric Botcazou
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 5a9627c4acf..c81900af970 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -6728,18 +6728,56 @@ gimplify_variable_sized_compare (tree *expr_p)
 static enum gimplify_status
 gimplify_scalar_mode_aggregate_compare (tree *expr_p)
 {
-  location_t loc = EXPR_LOCATION (*expr_p);
+  const location_t loc = EXPR_LOCATION (*expr_p);
+  const enum tree_code code = TREE_CODE (*expr_p);
   tree op0 = TREE_OPERAND (*expr_p, 0);
   tree op1 = TREE_OPERAND (*expr_p, 1);
-
   tree type = TREE_TYPE (op0);
   tree scalar_type = lang_hooks.types.type_for_mode (TYPE_MODE (type), 1);
 
   op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, scalar_type, op0);
   op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, scalar_type, op1);
 
-  *expr_p
-    = fold_build2_loc (loc, TREE_CODE (*expr_p), TREE_TYPE (*expr_p), op0, op1);
+  /* We need to perform ordering comparisons in memory order like memcmp and,
+     therefore, may need to byte-swap operands for little-endian targets.  */
+  if (code != EQ_EXPR && code != NE_EXPR)
+    {
+      gcc_assert (BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN);
+      gcc_assert (TREE_CODE (scalar_type) == INTEGER_TYPE);
+      tree fndecl;
+
+      if (BYTES_BIG_ENDIAN)
+	fndecl = NULL_TREE;
+      else
+	switch (int_size_in_bytes (scalar_type))
+	  {
+	  case 1:
+	    fndecl = NULL_TREE;
+	    break;
+	  case 2:
+	    fndecl = builtin_decl_implicit (BUILT_IN_BSWAP16);
+	    break;
+	  case 4:
+	    fndecl = builtin_decl_implicit (BUILT_IN_BSWAP32);
+	    break;
+	  case 8:
+	    fndecl = builtin_decl_implicit (BUILT_IN_BSWAP64);
+	    break;
+	  case 16:
+	    fndecl = builtin_decl_implicit (BUILT_IN_BSWAP128);
+	    break;
+	  default:
+	    gcc_unreachable ();
+	  }
+
+      if (fndecl)
+	{
+	  op0 = build_call_expr_loc (loc, fndecl, 1, op0);
+	  op1 = build_call_expr_loc (loc, fndecl, 1, op1);
+	}
+    }
+
+  *expr_p = fold_build2_loc (loc, code, TREE_TYPE (*expr_p), op0, op1);
 
   return GS_OK;
 }
-- { dg-do run }

with Array42_Pkg; use Array42_Pkg;

procedure Array42 is

  procedure Raise_Error_If_False (Test : Boolean; N : Positive) is
  begin
    if not Test then
      raise Program_Error with "Test" & N'Img & " fails";
    end if;
  end;

begin
  Raise_Error_If_False (LT2  ("12", "21"), 1);
  Raise_Error_If_False (LT4  ("1234", "4321"), 2);
  Raise_Error_If_False (LT8  ("12345678", "87654321"), 3);
  Raise_Error_If_False (LT8  ("12345678", "87654321"), 4);
  Raise_Error_If_False (LT16 ("12345678ABCDEFGH", "HGFEDCBA87654321"), 5);

  Raise_Error_If_False (LT5  ("12345", "54321"), 6);
  Raise_Error_If_False (LE5  ("12345", "54321"), 7);
  Raise_Error_If_False (not GT5  ("12345", "54321"), 8);
  Raise_Error_If_False (not GE5  ("12345", "54321"), 9);

  Raise_Error_If_False (LT45  ("1234", "12345"), 10);
  Raise_Error_If_False (not LT54  ("12345", "1234"), 11);
  Raise_Error_If_False (LT54  ("12345", "1235"), 12);

  Raise_Error_If_False (LT ("1234", "12345"), 13);
  Raise_Error_If_False (not LT ("12345", "1234"), 14);
  Raise_Error_If_False (LT ("12345", "1235"), 15);
end;
package Array42_Pkg is

  subtype S2  is String (1 .. 2);
  subtype S4  is String (1 .. 4);
  subtype S5  is String (1 .. 5);
  subtype S8  is String (1 .. 8);
  subtype S12 is String (1 .. 12);
  subtype S16 is String (1 .. 16);

  function LT2  (A, B : S2)  return Boolean is (A < B);
  function LT4  (A, B : S4)  return Boolean is (A < B);
  function LT8  (A, B : S8)  return Boolean is (A < B);
  function LT16 (A, B : S16) return Boolean is (A < B);

  function LT5  (A, B : S5)  return Boolean is (A < B);
  function LE5  (A, B : S5)  return Boolean is (A <= B);
  function GT5  (A, B : S5)  return Boolean is (A > B);
  function GE5  (A, B : S5)  return Boolean is (A >= B);

  function LT45 (A : S4; B : S5) return Boolean is (A < B);
  function LT54 (A : S5; B : S4) return Boolean is (A < B);

  function LT (A, B : String) return Boolean is (A < B);

end Array42_Pkg;

Reply via email to