2010-07-24  Sandra Loosemore  <sandra@codesourcery.com>

	Backport from mainline:

	2010-04-10  Wei Guozhi  <carrot@google.com>

	PR target/42601
	gcc/
	* config/arm/arm.c (arm_pic_static_addr): New function.
	(legitimize_pic_address): Call arm_pic_static_addr when it detects
	a static symbol.
	(arm_output_addr_const_extra): Output expression for new pattern.
	* config/arm/arm.md (UNSPEC_SYMBOL_OFFSET): New unspec symbol.

	2010-07-22  Sandra Loosemore  <sandra@codesourcery.com>

	PR tree-optimization/39839
	gcc/testsuite/
	* gcc.target/arm/pr39839.c: New test case.

 2010-07-24  Jie Zhang  <jie@codesourcery.com>
 
 	Issue #9079

=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c	2010-08-03 13:55:46 +0000
+++ new/gcc/config/arm/arm.c	2010-08-05 12:06:40 +0000
@@ -225,6 +225,7 @@
 static void arm_asm_trampoline_template (FILE *);
 static void arm_trampoline_init (rtx, tree, rtx);
 static rtx arm_trampoline_adjust_address (rtx);
+static rtx arm_pic_static_addr (rtx orig, rtx reg);
 
 
 /* Table of machine attributes.  */
@@ -4986,29 +4987,16 @@
     {
       rtx pic_ref, address;
       rtx insn;
-      int subregs = 0;
-
-      /* If this function doesn't have a pic register, create one now.  */
-      require_pic_register ();
 
       if (reg == 0)
 	{
 	  gcc_assert (can_create_pseudo_p ());
 	  reg = gen_reg_rtx (Pmode);
-
-	  subregs = 1;
+	  address = gen_reg_rtx (Pmode);
 	}
-
-      if (subregs)
-	address = gen_reg_rtx (Pmode);
       else
 	address = reg;
 
-      if (TARGET_32BIT)
-	emit_insn (gen_pic_load_addr_32bit (address, orig));
-      else /* TARGET_THUMB1 */
-	emit_insn (gen_pic_load_addr_thumb1 (address, orig));
-
       /* VxWorks does not impose a fixed gap between segments; the run-time
 	 gap can be different from the object-file gap.  We therefore can't
 	 use GOTOFF unless we are absolutely sure that the symbol is in the
@@ -5020,16 +5008,23 @@
 	       SYMBOL_REF_LOCAL_P (orig)))
 	  && NEED_GOT_RELOC
 	  && !TARGET_VXWORKS_RTP)
-	pic_ref = gen_rtx_PLUS (Pmode, cfun->machine->pic_reg, address);
+	insn = arm_pic_static_addr (orig, reg);
       else
 	{
+	  /* If this function doesn't have a pic register, create one now.  */
+	  require_pic_register ();
+
+	  if (TARGET_32BIT)
+	    emit_insn (gen_pic_load_addr_32bit (address, orig));
+	  else /* TARGET_THUMB1 */
+	    emit_insn (gen_pic_load_addr_thumb1 (address, orig));
+
 	  pic_ref = gen_const_mem (Pmode,
 				   gen_rtx_PLUS (Pmode, cfun->machine->pic_reg,
 					         address));
+	  insn = emit_move_insn (reg, pic_ref);
 	}
 
-      insn = emit_move_insn (reg, pic_ref);
-
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
 	 by loop.  */
       set_unique_reg_note (insn, REG_EQUAL, orig);
@@ -5236,6 +5231,43 @@
   emit_use (pic_reg);
 }
 
+/* Generate code to load the address of a static var when flag_pic is set.  */
+static rtx
+arm_pic_static_addr (rtx orig, rtx reg)
+{
+  rtx l1, labelno, offset_rtx, insn;
+
+  gcc_assert (flag_pic);
+
+  /* We use an UNSPEC rather than a LABEL_REF because this label
+     never appears in the code stream.  */
+  labelno = GEN_INT (pic_labelno++);
+  l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
+  l1 = gen_rtx_CONST (VOIDmode, l1);
+
+  /* On the ARM the PC register contains 'dot + 8' at the time of the
+     addition, on the Thumb it is 'dot + 4'.  */
+  offset_rtx = plus_constant (l1, TARGET_ARM ? 8 : 4);
+  offset_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, orig, offset_rtx),
+                               UNSPEC_SYMBOL_OFFSET);
+  offset_rtx = gen_rtx_CONST (Pmode, offset_rtx);
+
+  if (TARGET_32BIT)
+    {
+      emit_insn (gen_pic_load_addr_32bit (reg, offset_rtx));
+      if (TARGET_ARM)
+        insn = emit_insn (gen_pic_add_dot_plus_eight (reg, reg, labelno));
+      else
+        insn = emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
+    }
+  else /* TARGET_THUMB1 */
+    {
+      emit_insn (gen_pic_load_addr_thumb1 (reg, offset_rtx));
+      insn = emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
+    }
+
+  return insn;
+}
 
 /* Return nonzero if X is valid as an ARM state addressing register.  */
 static int
@@ -21461,6 +21493,16 @@
       fputc (')', fp);
       return TRUE;
     }
+  else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_SYMBOL_OFFSET)
+    {
+      output_addr_const (fp, XVECEXP (x, 0, 0));
+      if (GOT_PCREL)
+        fputs ("+.", fp);
+      fputs ("-(", fp);
+      output_addr_const (fp, XVECEXP (x, 0, 1));
+      fputc (')', fp);
+      return TRUE;
+    }
   else if (GET_CODE (x) == CONST_VECTOR)
     return arm_emit_vector_const (fp, x);
 

=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md	2010-07-30 14:17:05 +0000
+++ new/gcc/config/arm/arm.md	2010-08-05 12:06:40 +0000
@@ -101,6 +101,8 @@
 			  ; a given symbolic address.
    (UNSPEC_THUMB1_CASESI 25) ; A Thumb1 compressed dispatch-table call.
    (UNSPEC_RBIT 26)       ; rbit operation.
+   (UNSPEC_SYMBOL_OFFSET 27) ; The offset of the start of the symbol from
+                             ; another symbolic address.
   ]
 )
 

=== added file 'gcc/testsuite/gcc.target/arm/pr39839.c'
--- old/gcc/testsuite/gcc.target/arm/pr39839.c	1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/pr39839.c	2010-08-05 12:06:40 +0000
@@ -0,0 +1,24 @@
+/* { dg-options "-mthumb -Os -march=armv5te -mthumb-interwork -fpic" }  */
+/* { dg-require-effective-target arm_thumb1_ok } */
+/* { dg-final { scan-assembler-not "str\[\\t \]*r.,\[\\t \]*.sp," } } */
+
+struct S
+{
+  int count;
+  char *addr;
+};
+
+void func(const char*, const char*, int, const char*);
+
+/* This function should not need to spill to the stack. */
+void test(struct S *p)
+{
+  int off = p->count;
+  while (p->count >= 0)
+    {
+      const char *s = "xyz";
+      if (*p->addr) s = "pqr";
+      func("abcde", p->addr + off, off, s);
+      p->count--;
+    }
+}

