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.  */
