[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:
parent
deeec83de4
commit
d7c50d679f
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
"
|
||||
)
|
||||
|
@ -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
|
||||
|
32
gcc/testsuite/gcc.target/arm/pr89222.c
Normal file
32
gcc/testsuite/gcc.target/arm/pr89222.c
Normal 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} } } */
|
Loading…
Reference in New Issue
Block a user