[ARM] Fix PR89222

The GCC optimizer can generate symbols with non-zero offset from simple
if-statements. Bit zero is used for the Arm/Thumb state bit, so relocations
with offsets fail if it changes bit zero and the relocation forces bit zero
to true.  The fix is to disable offsets on function pointer symbols.  

    gcc/
	PR target/89222
	* config/arm/arm.md (movsi): Use targetm.cannot_force_const_mem
	to decide when to split off a non-zero offset from a symbol.
	* config/arm/arm.c (arm_cannot_force_const_mem): Disallow offsets
	in function symbols.

    testsuite/
	PR target/89222
	* gcc.target/arm/pr89222.c: Add new test.

From-SVN: r269390
This commit is contained in:
Wilco Dijkstra 2019-03-05 15:04:01 +00:00 committed by Wilco Dijkstra
parent deeec83de4
commit d7c50d679f
5 changed files with 67 additions and 41 deletions

View File

@ -1,3 +1,11 @@
2019-03-05 Wilco Dijkstra <wdijkstr@arm.com>
PR target/89222
* config/arm/arm.md (movsi): Use targetm.cannot_force_const_mem
to decide when to split off a non-zero offset from a symbol.
* config/arm/arm.c (arm_cannot_force_const_mem): Disallow offsets
in function symbols.
2019-03-05 Richard Biener <rguenther@suse.de>
PR tree-optimization/89594

View File

@ -8940,11 +8940,16 @@ static bool
arm_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
rtx base, offset;
split_const (x, &base, &offset);
if (ARM_OFFSETS_MUST_BE_WITHIN_SECTIONS_P)
if (SYMBOL_REF_P (base))
{
split_const (x, &base, &offset);
if (GET_CODE (base) == SYMBOL_REF
/* Function symbols cannot have an offset due to the Thumb bit. */
if ((SYMBOL_REF_FLAGS (base) & SYMBOL_FLAG_FUNCTION)
&& INTVAL (offset) != 0)
return true;
if (ARM_OFFSETS_MUST_BE_WITHIN_SECTIONS_P
&& !offset_within_block_p (base, INTVAL (offset)))
return true;
}

View File

@ -6016,53 +6016,29 @@
}
}
if (ARM_OFFSETS_MUST_BE_WITHIN_SECTIONS_P)
split_const (operands[1], &base, &offset);
if (INTVAL (offset) != 0
&& targetm.cannot_force_const_mem (SImode, operands[1]))
{
split_const (operands[1], &base, &offset);
if (GET_CODE (base) == SYMBOL_REF
&& !offset_within_block_p (base, INTVAL (offset)))
{
tmp = can_create_pseudo_p () ? gen_reg_rtx (SImode) : operands[0];
emit_move_insn (tmp, base);
emit_insn (gen_addsi3 (operands[0], tmp, offset));
DONE;
}
tmp = can_create_pseudo_p () ? gen_reg_rtx (SImode) : operands[0];
emit_move_insn (tmp, base);
emit_insn (gen_addsi3 (operands[0], tmp, offset));
DONE;
}
tmp = can_create_pseudo_p () ? NULL_RTX : operands[0];
/* Recognize the case where operand[1] is a reference to thread-local
data and load its address to a register. */
data and load its address to a register. Offsets have been split off
already. */
if (arm_tls_referenced_p (operands[1]))
{
rtx tmp = operands[1];
rtx addend = NULL;
if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
{
addend = XEXP (XEXP (tmp, 0), 1);
tmp = XEXP (XEXP (tmp, 0), 0);
}
gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0);
tmp = legitimize_tls_address (tmp,
!can_create_pseudo_p () ? operands[0] : 0);
if (addend)
{
tmp = gen_rtx_PLUS (SImode, tmp, addend);
tmp = force_operand (tmp, operands[0]);
}
operands[1] = tmp;
}
operands[1] = legitimize_tls_address (operands[1], tmp);
else if (flag_pic
&& (CONSTANT_P (operands[1])
|| symbol_mentioned_p (operands[1])
|| label_mentioned_p (operands[1])))
operands[1] = legitimize_pic_address (operands[1], SImode,
(!can_create_pseudo_p ()
? operands[0]
: NULL_RTX), NULL_RTX,
false /*compute_now*/);
operands[1] =
legitimize_pic_address (operands[1], SImode, tmp, NULL_RTX, false);
}
"
)

View File

@ -1,3 +1,8 @@
2019-03-05 Wilco Dijkstra <wdijkstr@arm.com>
PR target/89222
* gcc.target/arm/pr89222.c: Add new test.
2019-03-05 Richard Biener <rguenther@suse.de>
PR tree-optimization/89594

View File

@ -0,0 +1,32 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
void g (void);
void f1 (int x)
{
if (x != (int) g + 3)
return;
g();
}
void (*a2)(void);
void f2 (void)
{
a2 = &g + 3;
}
typedef void (*__sighandler_t)(int);
void handler (int);
void f3 (int x)
{
__sighandler_t h = &handler;
if (h != (__sighandler_t) 2 && h != (__sighandler_t) 1)
h (x);
}
/* { dg-final { scan-assembler-times {add(?:s)?\tr[0-9]+, r[0-9]+, #3} 2 } } */
/* { dg-final { scan-assembler-not {.word\tg\+3} } } */
/* { dg-final { scan-assembler-not {.word\thandler-1} } } */