From d7c50d679ffafaf5e7ba105cea765a307f60e2f3 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Tue, 5 Mar 2019 15:04:01 +0000 Subject: [PATCH] [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 --- gcc/ChangeLog | 8 ++++ gcc/config/arm/arm.c | 11 ++++-- gcc/config/arm/arm.md | 52 +++++++------------------- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.target/arm/pr89222.c | 32 ++++++++++++++++ 5 files changed, 67 insertions(+), 41 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/pr89222.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4fb2792c70d..d4e8cbe66af 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-03-05 Wilco Dijkstra + + 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 PR tree-optimization/89594 diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index f07f4cc47b6..69b74a237a5 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -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; } diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 7ee83a599f8..18059014b8b 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -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); } " ) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 529aa3cfd04..7c57390f83b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-03-05 Wilco Dijkstra + + PR target/89222 + * gcc.target/arm/pr89222.c: Add new test. + 2019-03-05 Richard Biener PR tree-optimization/89594 diff --git a/gcc/testsuite/gcc.target/arm/pr89222.c b/gcc/testsuite/gcc.target/arm/pr89222.c new file mode 100644 index 00000000000..d26d7df1754 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr89222.c @@ -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} } } */