 -      if (GET_MODE (index) != Pmode)
 +      /* Allow 32bit addr in 64bit mode - usually makes no sense except in LEA */
 +      if (GET_MODE (index) != SImode && (!TARGET_64BIT || GET_MODE (index) != DImode))
- 	{
--	  reason = "index is not in Pmode";
++	{
 +	  reason = "index is not in proper mode";
 +	  goto report_error;
 +	}
 +
 +      if (base && GET_MODE (base) != GET_MODE (index))
-+	{
+ 	{
+-	  reason = "index is not in Pmode";
 +	  reason = "index and base have different modes";
  	  goto report_error;
  	}
  
-@@ -9529,7 +9678,7 @@
-     new_rtx = addr;
-   else if (TARGET_64BIT
- 	   && ix86_cmodel != CM_SMALL_PIC
--	   && gotoff_operand (addr, Pmode))
-+	   && gotoff_operand (addr, ptr_mode))
+@@ -9514,7 +9663,9 @@
+   rtx addr = orig;
+   rtx new_rtx = orig;
+   rtx base;
++  enum machine_mode orig_mode;
+ 
++  orig_mode = GET_MODE(orig);
+ #if TARGET_MACHO
+   if (TARGET_MACHO && !TARGET_64BIT)
      {
-       rtx tmpreg;
+@@ -9562,7 +9713,7 @@
+ 	}
+       else new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmpreg);
+     }
+-  else if (!TARGET_64BIT && gotoff_operand (addr, Pmode))
++  else if (!TARGET_64BIT && gotoff_operand (addr, orig_mode))
+     {
        /* This symbol may be referenced via a displacement from the PIC
-@@ -9541,28 +9690,28 @@
+ 	 base address (@GOTOFF).  */
+@@ -9573,14 +9724,14 @@
  	addr = XEXP (addr, 0);
        if (GET_CODE (addr) == PLUS)
  	  {
 -            new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (addr, 0)),
-+            new_rtx = gen_rtx_UNSPEC (ptr_mode, gen_rtvec (1, XEXP (addr, 0)),
++            new_rtx = gen_rtx_UNSPEC (orig_mode, gen_rtvec (1, XEXP (addr, 0)),
  				      UNSPEC_GOTOFF);
 -	    new_rtx = gen_rtx_PLUS (Pmode, new_rtx, XEXP (addr, 1));
-+	    new_rtx = gen_rtx_PLUS (ptr_mode, new_rtx, XEXP (addr, 1));
- 	  }
- 	else
--          new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
--      new_rtx = gen_rtx_CONST (Pmode, new_rtx);
-+          new_rtx = gen_rtx_UNSPEC (ptr_mode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
-+      new_rtx = gen_rtx_CONST (ptr_mode, new_rtx);
-       if (!reg)
--        tmpreg = gen_reg_rtx (Pmode);
-+        tmpreg = gen_reg_rtx (ptr_mode);
-       else
- 	tmpreg = reg;
-       emit_move_insn (tmpreg, new_rtx);
- 
-       if (reg != 0)
- 	{
--	  new_rtx = expand_simple_binop (Pmode, PLUS, reg, pic_offset_table_rtx,
-+	  new_rtx = expand_simple_binop (ptr_mode, PLUS, reg, pic_offset_table_rtx,
- 					 tmpreg, 1, OPTAB_DIRECT);
- 	  new_rtx = reg;
- 	}
--      else new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmpreg);
-+      else new_rtx = gen_rtx_PLUS (ptr_mode, pic_offset_table_rtx, tmpreg);
-     }
--  else if (!TARGET_64BIT && gotoff_operand (addr, Pmode))
-+  else if (!TARGET_64BIT && gotoff_operand (addr, ptr_mode))
-     {
-       /* This symbol may be referenced via a displacement from the PIC
- 	 base address (@GOTOFF).  */
-@@ -9573,14 +9722,14 @@
- 	addr = XEXP (addr, 0);
-       if (GET_CODE (addr) == PLUS)
- 	  {
--            new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (addr, 0)),
-+            new_rtx = gen_rtx_UNSPEC (ptr_mode, gen_rtvec (1, XEXP (addr, 0)),
- 				      UNSPEC_GOTOFF);
--	    new_rtx = gen_rtx_PLUS (Pmode, new_rtx, XEXP (addr, 1));
-+	    new_rtx = gen_rtx_PLUS (ptr_mode, new_rtx, XEXP (addr, 1));
++	    new_rtx = gen_rtx_PLUS (orig_mode, new_rtx, XEXP (addr, 1));
  	  }
  	else
 -          new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
 -      new_rtx = gen_rtx_CONST (Pmode, new_rtx);
 -      new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new_rtx);
-+          new_rtx = gen_rtx_UNSPEC (ptr_mode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
-+      new_rtx = gen_rtx_CONST (ptr_mode, new_rtx);
-+      new_rtx = gen_rtx_PLUS (ptr_mode, pic_offset_table_rtx, new_rtx);
++          new_rtx = gen_rtx_UNSPEC (orig_mode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
++      new_rtx = gen_rtx_CONST (orig_mode, new_rtx);
++      new_rtx = gen_rtx_PLUS (orig_mode, pic_offset_table_rtx, new_rtx);
  
        if (reg != 0)
  	{
-@@ -9602,19 +9751,19 @@
+@@ -9602,19 +9753,19 @@
                && SYMBOL_REF_DLLIMPORT_P (XEXP (XEXP (addr, 0), 0)))
              {
                rtx t = legitimize_dllimport_symbol (XEXP (XEXP (addr, 0), 0), true);
 -              return gen_rtx_PLUS (Pmode, t, XEXP (XEXP (addr, 0), 1));
-+              return gen_rtx_PLUS (ptr_mode, t, XEXP (XEXP (addr, 0), 1));
++              return gen_rtx_PLUS (orig_mode, t, XEXP (XEXP (addr, 0), 1));
              }
          }
  

 		  if (reload_in_progress)
 		    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
-		  new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0),
+		  new_rtx = gen_rtx_UNSPEC (ptr_mode, gen_rtvec (1, op0),
 					    UNSPEC_GOTOFF);
-		  new_rtx = gen_rtx_PLUS (Pmode, new_rtx, op1);
-		  new_rtx = gen_rtx_CONST (Pmode, new_rtx);
-		  new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new_rtx);
+		  new_rtx = gen_rtx_PLUS (ptr_mode, new_rtx, op1);
+		  new_rtx = gen_rtx_CONST (ptr_mode, new_rtx);
+		  new_rtx = gen_rtx_PLUS (ptr_mode, pic_offset_table_rtx, new_rtx);
 
 		  if (reg != 0)
 		    {
@@ -9698,9 +9847,9 @@
 		  if (INTVAL (op1) < -16*1024*1024
 		      || INTVAL (op1) >= 16*1024*1024)
 		    {
-		      if (!x86_64_immediate_operand (op1, Pmode))
-			op1 = force_reg (Pmode, op1);
-		      new_rtx = gen_rtx_PLUS (Pmode, force_reg (Pmode, op0), op1);
+		      if (!x86_64_immediate_operand (op1, ptr_mode))
+			op1 = force_reg (ptr_mode, op1);
+		      new_rtx = gen_rtx_PLUS (ptr_mode, force_reg (ptr_mode, op0), op1);
 		    }
 		}
 	    }
@@ -9716,10 +9865,10 @@
 		{
 		  if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1)))
 		    {
-		      base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0));
+		      base = gen_rtx_PLUS (ptr_mode, base, XEXP (new_rtx, 0));
 		      new_rtx = XEXP (new_rtx, 1);
 		    }
-		  new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx);
+		  new_rtx = gen_rtx_PLUS (ptr_mode, base, new_rtx);
 		}
 	    }
 	}
@@ -9886,7 +10035,18 @@
       if (TARGET_64BIT || TARGET_ANY_GNU_TLS)
 	{
 	  base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS);
-	  return gen_rtx_PLUS (Pmode, base, off);
+          /* The following line of code prevents GCC from crashes while
+           * compiling TLS access.
+           * TODO(pasko): generate TLS access according to NaCl ABI.
+	   */
+	  if (Pmode != ptr_mode)
+	    {
+	      return gen_rtx_SUBREG(ptr_mode, gen_rtx_PLUS (Pmode, base, off), 0);
+	    }
+	  else
+	    {
+	      return gen_rtx_PLUS (Pmode, base, off);
+          }
 	}
       else
 	{
@@ -10166,7 +10319,21 @@
 	  rtx temp = gen_reg_rtx (Pmode);
 	  rtx val  = force_operand (XEXP (x, 1), temp);
 	  if (val != temp)

       break;
     default:
       gcc_unreachable ();
@@ -12329,6 +12522,7 @@
 {
   rtx op0, op1;
   enum tls_model model;
+  enum machine_mode op_mode;
 
   op0 = operands[0];
   op1 = operands[1];
@@ -12365,14 +12559,28 @@
       if (tmp)
 	{
 	  tmp = force_operand (tmp, NULL);
-	  tmp = expand_simple_binop (Pmode, PLUS, tmp, addend,
-				     op0, 1, OPTAB_DIRECT);
-	  if (tmp == op0)
-	    return;
+	  if (Pmode == ptr_mode)
+	    {
+	      tmp = expand_simple_binop (ptr_mode, PLUS, tmp, addend,
+				         op0, 1, OPTAB_DIRECT);
+	      if (tmp == op0)
+		return;
+	    }
+	   else
+	     {
+	       /* Lower the size of the constant ref operand in non-Pmode */
+	       tmp = gen_rtx_UNSPEC(ptr_mode, gen_rtvec(1, symbol), UNSPEC_TPOFF);
+	       tmp = gen_rtx_CONST(ptr_mode, tmp);
+	       tmp = gen_reg_rtx(ptr_mode);
+	       tmp = expand_simple_binop (ptr_mode, PLUS, tmp, addend,
+					  op0, 1, OPTAB_DIRECT);
+	       op1 = tmp;
+	     }
 	}
     }
 
-  if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
+  op_mode = GET_MODE(op0);
+  if (flag_pic && mode == op_mode && symbolic_operand (op1, op_mode))
     {
       if (TARGET_MACHO && !TARGET_64BIT)
 	{
@@ -12381,8 +12589,8 @@
 	    {
 	      rtx temp = ((reload_in_progress
 			   || ((op0 && REG_P (op0))
-			       && mode == Pmode))
-			  ? op0 : gen_reg_rtx (Pmode));
+			       && mode == op_mode))
+			  ? op0 : gen_reg_rtx (op_mode));
 	      op1 = machopic_indirect_data_reference (op1, temp);
 	      op1 = machopic_legitimize_pic_address (op1, mode,
 						     temp == op1 ? 0 : temp);
@@ -12396,8 +12604,8 @@
       else
 	{
 	  if (MEM_P (op0))
-	    op1 = force_reg (Pmode, op1);
-	  else if (!TARGET_64BIT || !x86_64_movabs_operand (op1, Pmode))
+	    op1 = force_reg (op_mode, op1);
+	  else if (!TARGET_64BIT || !x86_64_movabs_operand (op1, op_mode))
 	    {
 	      rtx reg = !can_create_pseudo_p () ? op0 : NULL_RTX;
 	      op1 = legitimize_pic_address (op1, reg);
@@ -12447,6 +12655,12 @@
 	}
     }
 
+  /* NaCl uses mixed 32bit/64bit mode and sometimes we need to move
+     32bit register to 64bit register at this point. x86-64 ABI
+     clears top half of 64bit register in all mov instructions thus
+     we can just use subregister move here. */
+  if (TARGET_64BIT && GET_MODE (op0) == SImode && GET_MODE(op1) == DImode)
+    op1 = simplify_gen_subreg (SImode, op1, DImode, 0);
   emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
 }
 
@@ -19048,7 +19262,7 @@
 {
   int i;
 
