Replace rip lea with eip

Fix for the POINTERS_EXTEND_UNSIGNED > 0 problem of keeping high part of rip.

Note that ix86_lea_decompose_address does not produce pc_rtx in base or index even if -fPIC is used: pc_rtx is added later in print_operand_address_parts. That's why we are handling !base and !index case here.

BUG=http://code.google.com/p/nativeclient/issues/detail?id=1304
TEST=see reproducer in bug above

R=eaeltsin@google.com

Review URL: https://chromiumcodereview.appspot.com/10386087
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index a79d1af..5fb532b 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -264,6 +264,7 @@
 extern int lea_match_address_operand (rtx, enum machine_mode);
 extern int ix86_decompose_address (rtx, struct ix86_address *);
 extern int ix86_lea_decompose_address (rtx, struct ix86_address *);
+extern int nacl_address_uses_special_registers (rtx);
 extern int memory_address_length (rtx addr);
 extern void x86_output_aligned_bss (FILE *, tree, const char *,
 				    unsigned HOST_WIDE_INT, int);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 8f0111a..fc37c41 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -9082,6 +9082,42 @@
   return retval;
 }
 
+
+/* Returns true if NaCl-special registers are used: %rbp, %rsp, %rip.  */
+int
+nacl_address_uses_special_registers (rtx op)
+{
+  if (TARGET_NACL)
+    {
+      struct ix86_address parts;
+      rtx symbol;
+      int ok;
+
+      ok = ix86_lea_decompose_address (op, &parts);
+      gcc_assert (ok);
+
+      /* Check for %rbp/%rsp.  */
+      if (parts.base &&
+	  (REGNO (parts.base) == SP_REG || REGNO (parts.base) == BP_REG))
+	return 1;
+
+      /* Checks for %rip are borrowed from print_operand_address_parts.  */
+      if (!parts.base && !parts.index)
+	{
+	  symbol = parts.disp;
+	  if (GET_CODE (symbol) == CONST
+	      && GET_CODE (XEXP (symbol, 0)) == PLUS
+	      && CONST_INT_P (XEXP (XEXP (symbol, 0), 1)))
+	    symbol = XEXP (XEXP (symbol, 0), 0);
+	  if (GET_CODE (symbol) == SYMBOL_REF ||
+	      GET_CODE (symbol) == LABEL_REF)
+	    return 1;
+	}
+    }
+
+  return 0;
+}
+
 int
 lea_match_address_operand (rtx op, enum machine_mode mode)
 {
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 8dc1bdd..6429360 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -2415,6 +2415,8 @@
       return "#";
 
     case TYPE_LEA:
+      if (nacl_address_uses_special_registers (operands[1]))
+	return "lea{l}\t{%a1, %k0|%k0, %a1}";
       return "lea{q}\t{%a1, %0|%0, %a1}";
 
     default:
@@ -6008,20 +6010,8 @@
 	(match_operand:DI 1 "lea_address_operand" "T"))]
   "TARGET_64BIT"
 {
-  if (TARGET_NACL)
-    {
-      struct ix86_address parts;
-      int ok;
-
-      ok = ix86_lea_decompose_address (operands[1], &parts);
-      gcc_assert (ok);
-
-      if (parts.base)
-	{
-	  if (REGNO (parts.base) == SP_REG || REGNO (parts.base) == BP_REG)
-	    return "lea{l}\t{%Z1, %k0|%k0, %Z1}";
-	}
-    }
+  if (nacl_address_uses_special_registers (operands[1]))
+    return "lea{l}\t{%Z1, %k0|%k0, %Z1}";
   return "lea{q}\t{%Z1, %0|%0, %Z1}";
 }
   [(set_attr "type" "lea")