2010-07-24 Sandra Loosemore Backport from mainline: 2010-04-10 Wei Guozhi 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 PR tree-optimization/39839 gcc/testsuite/ * gcc.target/arm/pr39839.c: New test case. 2010-07-24 Jie Zhang 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--; + } +}