Hi,

TARGET_MEM_REF only works on ptr_mode.  That means base and index parts
of x86 address operand in x32 mode may be in ptr_mode.  This patch
supports 32bit base and index parts in x32 mode.  OK for trunk?

Thanks.


H.J.
---
2011-07-09  H.J. Lu  <hongjiu...@intel.com>

        * config/i386/i386.c (ix86_simplify_base_index_disp): New.
        (ix86_decompose_address): Support 32bit address in x32 mode.
        (ix86_legitimate_address_p): Likewise.
        (ix86_fixup_binary_operands): Likewise.

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 04cb07d..c852719 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -10984,6 +11010,190 @@ ix86_live_on_entry (bitmap regs)
     }
 }
 
+/* For TARGET_X32, IRA may generate
+
+   (set (reg:SI 40 r11)
+        (plus:SI (plus:SI (mult:SI (reg:SI 1 dx)
+                                  (const_int 8))
+                         (subreg:SI (plus:DI (reg/f:DI 7 sp)
+                                             (const_int CONST1)) 0))
+                (const_int CONST2)))
+
+   We translate it into
+
+   (set (reg:SI 40 r11)
+        (plus:SI (plus:SI (mult:SI (reg:SI 1 dx)
+                                  (const_int 8))
+                         (reg/f:SI 7 sp))
+                (const_int [CONST1 + CONST2])))
+
+   We also translate
+
+   (plus:DI (zero_extend:DI (plus:SI (plus:SI (reg:SI 4 si [70])
+                                             (reg:SI 2 cx [86]))
+                                    (const_int CONST1)))
+           (const_int CONST2))
+
+   into
+
+   (plus:DI (zero_extend:DI (plus:SI (reg:SI 4 si [70])
+                                    (reg:SI 2 cx [86]))
+           (const_int [CONST1 + CONST2])))
+
+   We also translate
+
+   (plus:SI (plus:SI (plus:SI (reg:SI 4 si [70])
+                             (reg:SI 2 cx [86]))
+                    (symbol_ref:SI ("A.193.2210")))
+           (const_int CONST))
+
+   into
+
+   (plus:SI (plus:SI (reg:SI 4 si [70])
+                    (reg:SI 2 cx [86]))
+           (const (plus:SI (symbol_ref:SI ("A.193.2210"))
+                           (const_int CONST))))
+
+   We also translate
+
+   (plus:SI (reg:SI 0 ax [orig:74 D.4067 ] [74])
+           (subreg:SI (plus:DI (reg/f:DI 7 sp)
+                               (const_int 64 [0x40])) 0))
+
+   into
+
+   (plus:SI (reg:SI 0 ax [orig:74 D.4067 ] [74])
+           (plus:SI (reg/f:SI 7 sp) (const_int 64 [0x40])))
+
+   If PLUS is true, we also translate
+
+   (set (reg:SI 40 r11)
+        (plus:SI (plus:SI (reg:SI 1 dx)
+                         (subreg:SI (plus:DI (reg/f:DI 7 sp)
+                                             (const_int CONST1)) 0))
+                (const_int CONST2)))
+
+   into
+
+   (set (reg:SI 40 r11)
+        (plus:SI (plus:SI (reg:SI 1 dx)
+                         (reg/f:SI 7 sp))
+                (const_int [CONST1 + CONST2])))
+
+ */
+
+static void
+ix86_simplify_base_index_disp (rtx *base_p, rtx *index_p, rtx *disp_p,
+                              bool plus)
+{
+  rtx base = *base_p;
+  rtx disp, index, op0, op1;
+
+  if (!base || GET_MODE (base) != ptr_mode)
+    return;
+
+  disp = *disp_p;
+  if (disp != NULL_RTX
+      && disp != const0_rtx
+      && !CONST_INT_P (disp))
+    return;
+
+  if (GET_CODE (base) == SUBREG)
+    base = SUBREG_REG (base);
+
+  if (GET_CODE (base) == PLUS)
+    {
+      rtx addend;
+
+      op0 = XEXP (base, 0);
+      op1 = XEXP (base, 1);
+
+      if ((REG_P (op0)
+          || (!plus
+              && GET_CODE (op0) == PLUS
+              && GET_MODE (op0) == ptr_mode
+              && REG_P (XEXP (op0, 0))
+              && REG_P (XEXP (op0, 1))))
+         && (CONST_INT_P (op1)
+             || GET_CODE (op1) == SYMBOL_REF
+             || GET_CODE (op1) == LABEL_REF))
+       {
+         base = op0;
+         addend = op1;
+       }
+      else if (REG_P (op1)
+              && (CONST_INT_P (op0)
+                  || GET_CODE (op0) == SYMBOL_REF
+                  || GET_CODE (op0) == LABEL_REF))
+       {
+         base = op1;
+         addend = op0;
+       }
+      else if (plus
+              && GET_CODE (op1) == SUBREG
+              && GET_MODE (op1) == ptr_mode)
+       {
+         op1 = SUBREG_REG (op1);
+         if (GET_CODE (op1) == PLUS)
+           {
+             addend = XEXP (op1, 1);
+             op1 = XEXP (op1, 0);
+             if (REG_P (op1) && CONST_INT_P (addend))
+               {
+                 op1 = gen_rtx_REG (ptr_mode, REGNO (op1));
+                 *base_p = gen_rtx_PLUS (ptr_mode, op0, op1);
+               }
+             else
+               return;
+           }
+         else
+           return;
+       }
+      else
+       return;
+
+      if (disp == NULL_RTX || disp == const0_rtx)
+       *disp_p = addend;
+      else
+       {
+         if (CONST_INT_P (addend))
+           *disp_p = GEN_INT (INTVAL (disp) + INTVAL (addend));
+         else
+           {
+             disp = gen_rtx_PLUS (ptr_mode, addend, disp);
+             *disp_p = gen_rtx_CONST (ptr_mode, disp);
+           }
+       }
+
+      if (!plus)
+       {
+         if (REG_P (base))
+           *base_p = gen_rtx_REG (ptr_mode, REGNO (base));
+         else
+           *base_p = base;
+       }
+    }
+  else if (!plus
+          && (disp == NULL_RTX || disp == const0_rtx)
+          && index_p
+          && (index = *index_p) != NULL_RTX
+          && GET_CODE (index) == SUBREG
+          && GET_MODE (index) == ptr_mode)
+    {
+      index = SUBREG_REG (index);
+      if (GET_CODE (index) == PLUS && GET_MODE (index) == Pmode)
+       {
+         op0 = XEXP (index, 0);
+         op1 = XEXP (index, 1);
+         if (REG_P (op0) && CONST_INT_P (op1))
+           {
+             *index_p = gen_rtx_REG (ptr_mode, REGNO (op0));
+             *disp_p = op1;
+           }
+       }
+    }
+}
+
 /* Extract the parts of an RTL expression that is a valid memory address
    for an instruction.  Return 0 if the structure of the address is
    grossly off.  Return -1 if the address contains ASHIFT, so it is not
@@ -11000,6 +11210,13 @@ ix86_decompose_address (rtx addr, struct ix86_address 
*out)
   int retval = 1;
   enum ix86_address_seg seg = SEG_DEFAULT;
 
+  /* Support 32bit address in x32 mode.  */
+  if (TARGET_X32
+      && GET_CODE (addr) == ZERO_EXTEND
+      && GET_MODE (addr) == Pmode
+      && GET_CODE (XEXP (addr, 0)) == PLUS)
+    addr = XEXP (addr, 0);
+
   if (REG_P (addr) || GET_CODE (addr) == SUBREG)
     base = addr;
   else if (GET_CODE (addr) == PLUS)
@@ -11014,6 +11231,24 @@ ix86_decompose_address (rtx addr, struct ix86_address 
*out)
            return 0;
          addends[n++] = XEXP (op, 1);
          op = XEXP (op, 0);
+         /* Support 32bit address in x32 mode.  */
+         if (TARGET_X32 && reload_completed)
+           {
+             if (GET_CODE (op) == ZERO_EXTEND
+                 && GET_MODE (op) == Pmode
+                 && GET_CODE (XEXP (op, 0)) == PLUS)
+               {
+                 op = XEXP (op, 0);
+                 if (n == 1)
+                   ix86_simplify_base_index_disp (&op, NULL,
+                                                  &addends[0], false);
+               }
+             else if (n == 1
+                      && GET_CODE (op) == PLUS
+                      && GET_MODE (op) == ptr_mode)
+               ix86_simplify_base_index_disp (&op, NULL, &addends[0],
+                                              true);
+           }
        }
       while (GET_CODE (op) == PLUS);
       if (n >= 4)
@@ -11107,13 +11342,17 @@ ix86_decompose_address (rtx addr, struct ix86_address 
*out)
       scale = INTVAL (scale_rtx);
     }
 
-  base_reg = base && GET_CODE (base) == SUBREG ? SUBREG_REG (base) : base;
-  index_reg = index && GET_CODE (index) == SUBREG ? SUBREG_REG (index) : index;
+  if (TARGET_X32 && reload_completed)
+    ix86_simplify_base_index_disp (&base, &index, &disp, false);
 
   /* Avoid useless 0 displacement.  */
   if (disp == const0_rtx && (base || index))
     disp = NULL_RTX;
 
+  index_reg = index && GET_CODE (index) == SUBREG ? SUBREG_REG (index) : index;
+
+  base_reg = base && GET_CODE (base) == SUBREG ? SUBREG_REG (base) : base;
+
   /* Allow arg pointer and stack pointer as index if there is not scaling.  */
   if (base_reg && index_reg && scale == 1
       && (index_reg == arg_pointer_rtx
@@ -11522,6 +11761,7 @@ ix86_legitimate_address_p (enum machine_mode mode 
ATTRIBUTE_UNUSED,
   struct ix86_address parts;
   rtx base, index, disp;
   HOST_WIDE_INT scale;
+  enum machine_mode base_mode;
 
   if (ix86_decompose_address (addr, &parts) <= 0)
     /* Decomposition failed.  */
@@ -11553,8 +11793,11 @@ ix86_legitimate_address_p (enum machine_mode mode 
ATTRIBUTE_UNUSED,
        /* Base is not a register.  */
        return false;
 
-      if (GET_MODE (base) != Pmode)
-       /* Base is not in Pmode.  */
+      base_mode = GET_MODE (base);
+      if (base_mode != Pmode
+         && !(TARGET_X32
+              && base_mode == ptr_mode))
+       /* Base is not in Pmode nor ptr_mode.  */
        return false;
 
       if ((strict && ! REG_OK_FOR_BASE_STRICT_P (reg))
@@ -11562,6 +11805,8 @@ ix86_legitimate_address_p (enum machine_mode mode 
ATTRIBUTE_UNUSED,
        /* Base is not valid.  */
        return false;
     }
+  else
+    base_mode = VOIDmode;
 
   /* Validate index register.
 
@@ -11570,6 +11815,7 @@ ix86_legitimate_address_p (enum machine_mode mode 
ATTRIBUTE_UNUSED,
   if (index)
     {
       rtx reg;
+      enum machine_mode index_mode;
 
       if (REG_P (index))
        reg = index;
@@ -11582,8 +11828,13 @@ ix86_legitimate_address_p (enum machine_mode mode 
ATTRIBUTE_UNUSED,
        /* Index is not a register.  */
        return false;
 
-      if (GET_MODE (index) != Pmode)
-       /* Index is not in Pmode.  */
+      index_mode = GET_MODE (index);
+      if ((base_mode != VOIDmode
+          && base_mode != index_mode)
+          || (index_mode != Pmode
+              && !(TARGET_X32
+                   && index_mode == ptr_mode)))
+       /* Index is not in Pmode nor ptr_mode.  */
        return false;
 
       if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (reg))
@@ -15461,6 +15757,16 @@ ix86_fixup_binary_operands (enum rtx_code code, enum 
machine_mode mode,
       else
        src2 = force_reg (mode, src2);
     }
+  else
+    {
+      /* Support 32bit address in x32 mode.  */
+      if (TARGET_X32
+         && code == PLUS
+         && !MEM_P (dst)
+         && !MEM_P (src1)
+         && MEM_P (src2) )
+       src2 = force_reg (mode, src2);
+    }
 
   /* If the destination is memory, and we do not have matching source
      operands, do things in registers.  */

Reply via email to