]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Tweak base/index disambiguation in decompose_normal_address [PR116236]
authorRichard Sandiford <richard.sandiford@arm.com>
Thu, 15 Aug 2024 15:54:03 +0000 (16:54 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Thu, 15 Aug 2024 15:54:03 +0000 (16:54 +0100)
The PR points out that, for an address like:

  (plus (zero_extend X) Y)

decompose_normal_address doesn't establish a strong preference
between treating X as the base or Y as the base.  As the comment
in the patch says, zero_extend isn't enough on its own to assume
an index, at least not on POINTERS_EXTEND_UNSIGNED targets.
But in a construct like the one above, X and Y have different modes,
and it seems reasonable to assume that the one with the expected
address mode is the base.

This matters on targets like m68k that support index extension
and that require different classes for bases and indices.

gcc/
PR middle-end/116236
* rtlanal.cc (decompose_normal_address): Try to distinguish
bases and indices based on mode, before resorting to "baseness".

gcc/rtlanal.cc

index 4158a531bdd71d5ec69aa806c17502d70ee2c585..71207ee4f417ac40f8c8dea5dcda78956ef89108 100644 (file)
@@ -6724,20 +6724,36 @@ decompose_normal_address (struct address_info *info)
     }
   else if (out == 2)
     {
+      auto address_mode = targetm.addr_space.address_mode (info->as);
+      rtx inner_op0 = *inner_ops[0];
+      rtx inner_op1 = *inner_ops[1];
+      int base;
+      /* If one inner operand has the expected mode for a base and the other
+        doesn't, assume that the other one is the index.  This is useful
+        for addresses such as:
+
+          (plus (zero_extend X) Y)
+
+        zero_extend is not in itself enough to assume an index, since bases
+        can be zero-extended on POINTERS_EXTEND_UNSIGNED targets.  But if
+        Y has address mode and X doesn't, there should be little doubt that
+        Y is the base.  */
+      if (GET_MODE (inner_op0) == address_mode
+         && GET_MODE (inner_op1) != address_mode)
+       base = 0;
+      else if (GET_MODE (inner_op1) == address_mode
+              && GET_MODE (inner_op0) != address_mode)
+       base = 1;
       /* In the event of a tie, assume the base comes first.  */
-      if (baseness (*inner_ops[0], info->mode, info->as, PLUS,
-                   GET_CODE (*ops[1]))
-         >= baseness (*inner_ops[1], info->mode, info->as, PLUS,
-                      GET_CODE (*ops[0])))
-       {
-         set_address_base (info, ops[0], inner_ops[0]);
-         set_address_index (info, ops[1], inner_ops[1]);
-       }
+      else if (baseness (inner_op0, info->mode, info->as, PLUS,
+                        GET_CODE (*ops[1]))
+              >= baseness (inner_op1, info->mode, info->as, PLUS,
+                           GET_CODE (*ops[0])))
+       base = 0;
       else
-       {
-         set_address_base (info, ops[1], inner_ops[1]);
-         set_address_index (info, ops[0], inner_ops[0]);
-       }
+       base = 1;
+      set_address_base (info, ops[base], inner_ops[base]);
+      set_address_index (info, ops[1 - base], inner_ops[1 - base]);
     }
   else
     gcc_assert (out == 0);