[v3] x86: Handle TARGET_INDIRECT_BRANCH_REGISTER for -fno-plt
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-arm |
success
|
Test passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 |
success
|
Test passed
|
Commit Message
If TARGET_INDIRECT_BRANCH_REGISTER is true, indirect call and jump should
use register, not memory. Update Bs, Bw and Bz constraints to disable
indirect call over memmory if TARGET_INDIRECT_BRANCH_REGISTER true, change
x32 call over GOT slot to call over register and also disable sibcall
over memory.
gcc/
PR target/118713
* config/i386/constraints.md (Bs): Always disable if
TARGET_INDIRECT_BRANCH_REGISTER is true.
(Bw): Likewise.
* config/i386/i386-expand.cc (ix86_expand_call): Force indirect
call via register for GOT slot call if
TARGET_INDIRECT_BRANCH_REGISTER is true.
* config/i386/i386-protos.h (ix86_nopic_noplt_attribute_p): New.
* config/i386/i386.cc (ix86_nopic_noplt_attribute_p): Make it
global.
* config/i386/i386.md (*call_got_x32): Disable indirect call via
memory for TARGET_INDIRECT_BRANCH_REGISTER.
(*call_value_got_x32): Likewise.
(*sibcall_value_pop_memory): Likewise.
* config/i386/predicates.md (constant_call_address_operand):
Return false if both TARGET_INDIRECT_BRANCH_REGISTER and
ix86_nopic_noplt_attribute_p are true.
gcc/testsuite/
PR target/118713
* gcc.target/i386/pr118713-1-x32.c: New test.
* gcc.target/i386/pr118713-1.c: Likewise.
* gcc.target/i386/pr118713-2-x32.c: Likewise.
* gcc.target/i386/pr118713-2.c: Likewise.
* gcc.target/i386/pr118713-3-x32.c: Likewise.
* gcc.target/i386/pr118713-3.c: Likewise.
* gcc.target/i386/pr118713-4-x32.c: Likewise.
* gcc.target/i386/pr118713-4.c: Likewise.
* gcc.target/i386/pr118713-5-x32.c: Likewise.
* gcc.target/i386/pr118713-5.c: Likewise.
* gcc.target/i386/pr118713-6-x32.c: Likewise.
* gcc.target/i386/pr118713-6.c: Likewise.
* gcc.target/i386/pr118713-7-x32.c: Likewise.
* gcc.target/i386/pr118713-7.c: Likewise.
* gcc.target/i386/pr118713-8-x32.c: Likewise.
* gcc.target/i386/pr118713-8.c: Likewise.
* gcc.target/i386/pr118713-9-x32.c: Likewise.
* gcc.target/i386/pr118713-9.c: Likewise.
* gcc.target/i386/pr118713-10-x32.c: Likewise.
* gcc.target/i386/pr118713-10.c: Likewise.
* gcc.target/i386/pr118713-11-x32.c: Likewise.
* gcc.target/i386/pr118713-11.c: Likewise.
* gcc.target/i386/pr118713-12-x32.c: Likewise.
* gcc.target/i386/pr118713-12.c: Likewise.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
gcc/config/i386/constraints.md | 24 +++++++++----------
gcc/config/i386/i386-expand.cc | 22 +++++++++++------
gcc/config/i386/i386-protos.h | 1 +
gcc/config/i386/i386.cc | 2 +-
gcc/config/i386/i386.md | 6 ++---
gcc/config/i386/predicates.md | 4 +++-
.../gcc.target/i386/pr118713-1-x32.c | 8 +++++++
gcc/testsuite/gcc.target/i386/pr118713-1.c | 14 +++++++++++
.../gcc.target/i386/pr118713-10-x32.c | 8 +++++++
gcc/testsuite/gcc.target/i386/pr118713-10.c | 15 ++++++++++++
.../gcc.target/i386/pr118713-11-x32.c | 8 +++++++
gcc/testsuite/gcc.target/i386/pr118713-11.c | 14 +++++++++++
.../gcc.target/i386/pr118713-12-x32.c | 8 +++++++
gcc/testsuite/gcc.target/i386/pr118713-12.c | 14 +++++++++++
.../gcc.target/i386/pr118713-2-x32.c | 8 +++++++
gcc/testsuite/gcc.target/i386/pr118713-2.c | 15 ++++++++++++
.../gcc.target/i386/pr118713-3-x32.c | 8 +++++++
gcc/testsuite/gcc.target/i386/pr118713-3.c | 14 +++++++++++
.../gcc.target/i386/pr118713-4-x32.c | 8 +++++++
gcc/testsuite/gcc.target/i386/pr118713-4.c | 14 +++++++++++
.../gcc.target/i386/pr118713-5-x32.c | 7 ++++++
gcc/testsuite/gcc.target/i386/pr118713-5.c | 12 ++++++++++
.../gcc.target/i386/pr118713-6-x32.c | 7 ++++++
gcc/testsuite/gcc.target/i386/pr118713-6.c | 13 ++++++++++
.../gcc.target/i386/pr118713-7-x32.c | 7 ++++++
gcc/testsuite/gcc.target/i386/pr118713-7.c | 12 ++++++++++
.../gcc.target/i386/pr118713-8-x32.c | 7 ++++++
gcc/testsuite/gcc.target/i386/pr118713-8.c | 12 ++++++++++
.../gcc.target/i386/pr118713-9-x32.c | 8 +++++++
gcc/testsuite/gcc.target/i386/pr118713-9.c | 14 +++++++++++
30 files changed, 290 insertions(+), 24 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-1-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-1.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-10-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-10.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-11-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-11.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-12-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-12.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-2-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-2.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-3-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-3.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-4-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-4.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-5-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-5.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-6-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-6.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-7-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-7.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-8-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-8.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-9-x32.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-9.c
Comments
On Sat, Feb 1, 2025 at 9:51 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> If TARGET_INDIRECT_BRANCH_REGISTER is true, indirect call and jump should
> use register, not memory. Update Bs, Bw and Bz constraints to disable
> indirect call over memmory if TARGET_INDIRECT_BRANCH_REGISTER true, change
> x32 call over GOT slot to call over register and also disable sibcall
> over memory.
>
> gcc/
>
> PR target/118713
> * config/i386/constraints.md (Bs): Always disable if
> TARGET_INDIRECT_BRANCH_REGISTER is true.
> (Bw): Likewise.
> * config/i386/i386-expand.cc (ix86_expand_call): Force indirect
> call via register for GOT slot call if
> TARGET_INDIRECT_BRANCH_REGISTER is true.
> * config/i386/i386-protos.h (ix86_nopic_noplt_attribute_p): New.
> * config/i386/i386.cc (ix86_nopic_noplt_attribute_p): Make it
> global.
> * config/i386/i386.md (*call_got_x32): Disable indirect call via
> memory for TARGET_INDIRECT_BRANCH_REGISTER.
> (*call_value_got_x32): Likewise.
> (*sibcall_value_pop_memory): Likewise.
> * config/i386/predicates.md (constant_call_address_operand):
> Return false if both TARGET_INDIRECT_BRANCH_REGISTER and
> ix86_nopic_noplt_attribute_p are true.
LGTM, with some code reshuffling, proposed below. I didn't do a
thorough review on how T_I_B_R is handled, you are the expert in the
area of symbol handling.
Thanks,
Uros.
>
> gcc/testsuite/
>
> PR target/118713
> * gcc.target/i386/pr118713-1-x32.c: New test.
> * gcc.target/i386/pr118713-1.c: Likewise.
> * gcc.target/i386/pr118713-2-x32.c: Likewise.
> * gcc.target/i386/pr118713-2.c: Likewise.
> * gcc.target/i386/pr118713-3-x32.c: Likewise.
> * gcc.target/i386/pr118713-3.c: Likewise.
> * gcc.target/i386/pr118713-4-x32.c: Likewise.
> * gcc.target/i386/pr118713-4.c: Likewise.
> * gcc.target/i386/pr118713-5-x32.c: Likewise.
> * gcc.target/i386/pr118713-5.c: Likewise.
> * gcc.target/i386/pr118713-6-x32.c: Likewise.
> * gcc.target/i386/pr118713-6.c: Likewise.
> * gcc.target/i386/pr118713-7-x32.c: Likewise.
> * gcc.target/i386/pr118713-7.c: Likewise.
> * gcc.target/i386/pr118713-8-x32.c: Likewise.
> * gcc.target/i386/pr118713-8.c: Likewise.
> * gcc.target/i386/pr118713-9-x32.c: Likewise.
> * gcc.target/i386/pr118713-9.c: Likewise.
> * gcc.target/i386/pr118713-10-x32.c: Likewise.
> * gcc.target/i386/pr118713-10.c: Likewise.
> * gcc.target/i386/pr118713-11-x32.c: Likewise.
> * gcc.target/i386/pr118713-11.c: Likewise.
> * gcc.target/i386/pr118713-12-x32.c: Likewise.
> * gcc.target/i386/pr118713-12.c: Likewise.
>
> Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> ---
> gcc/config/i386/constraints.md | 24 +++++++++----------
> gcc/config/i386/i386-expand.cc | 22 +++++++++++------
> gcc/config/i386/i386-protos.h | 1 +
> gcc/config/i386/i386.cc | 2 +-
> gcc/config/i386/i386.md | 6 ++---
> gcc/config/i386/predicates.md | 4 +++-
> .../gcc.target/i386/pr118713-1-x32.c | 8 +++++++
> gcc/testsuite/gcc.target/i386/pr118713-1.c | 14 +++++++++++
> .../gcc.target/i386/pr118713-10-x32.c | 8 +++++++
> gcc/testsuite/gcc.target/i386/pr118713-10.c | 15 ++++++++++++
> .../gcc.target/i386/pr118713-11-x32.c | 8 +++++++
> gcc/testsuite/gcc.target/i386/pr118713-11.c | 14 +++++++++++
> .../gcc.target/i386/pr118713-12-x32.c | 8 +++++++
> gcc/testsuite/gcc.target/i386/pr118713-12.c | 14 +++++++++++
> .../gcc.target/i386/pr118713-2-x32.c | 8 +++++++
> gcc/testsuite/gcc.target/i386/pr118713-2.c | 15 ++++++++++++
> .../gcc.target/i386/pr118713-3-x32.c | 8 +++++++
> gcc/testsuite/gcc.target/i386/pr118713-3.c | 14 +++++++++++
> .../gcc.target/i386/pr118713-4-x32.c | 8 +++++++
> gcc/testsuite/gcc.target/i386/pr118713-4.c | 14 +++++++++++
> .../gcc.target/i386/pr118713-5-x32.c | 7 ++++++
> gcc/testsuite/gcc.target/i386/pr118713-5.c | 12 ++++++++++
> .../gcc.target/i386/pr118713-6-x32.c | 7 ++++++
> gcc/testsuite/gcc.target/i386/pr118713-6.c | 13 ++++++++++
> .../gcc.target/i386/pr118713-7-x32.c | 7 ++++++
> gcc/testsuite/gcc.target/i386/pr118713-7.c | 12 ++++++++++
> .../gcc.target/i386/pr118713-8-x32.c | 7 ++++++
> gcc/testsuite/gcc.target/i386/pr118713-8.c | 12 ++++++++++
> .../gcc.target/i386/pr118713-9-x32.c | 8 +++++++
> gcc/testsuite/gcc.target/i386/pr118713-9.c | 14 +++++++++++
> 30 files changed, 290 insertions(+), 24 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-1-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-1.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-10-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-10.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-11-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-11.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-12-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-12.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-2-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-2.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-3-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-3.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-4-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-4.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-5-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-5.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-6-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-6.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-7-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-7.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-8-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-8.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-9-x32.c
> create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-9.c
>
> diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
> index 9dd280568bd..d3d6e9e66f4 100644
> --- a/gcc/config/i386/constraints.md
> +++ b/gcc/config/i386/constraints.md
> @@ -203,21 +203,21 @@ (define_special_memory_constraint "Br"
>
> (define_constraint "Bs"
> "@internal Sibcall memory operand."
> - (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
> - (not (match_test "TARGET_X32"))
> - (match_operand 0 "sibcall_memory_operand"))
> - (and (match_test "TARGET_X32")
> - (match_test "Pmode == DImode")
> - (match_operand 0 "GOT_memory_operand"))))
> + (and (match_test "!TARGET_INDIRECT_BRANCH_REGISTER")
> + (ior (and (match_test "!TARGET_X32")
> + (match_operand 0 "sibcall_memory_operand"))
> + (and (match_test "TARGET_X32")
> + (match_test "Pmode == DImode")
> + (match_operand 0 "GOT_memory_operand")))))
While here, the above can use if_then_else RTX (and not RTX for
consistency), like:
(and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
(if_then_else (match_test "TARGET_X32")
(and (match_test "Pmode == DImode")
(match_operand 0 "GOT_memory_operand"))
(match_operand 0 "sibcall_memory_operand")))
> (define_constraint "Bw"
> "@internal Call memory operand."
> - (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
> - (not (match_test "TARGET_X32"))
> - (match_operand 0 "memory_operand"))
> - (and (match_test "TARGET_X32")
> - (match_test "Pmode == DImode")
> - (match_operand 0 "GOT_memory_operand"))))
> + (and (match_test "!TARGET_INDIRECT_BRANCH_REGISTER")
> + (ior (and (match_test "!TARGET_X32")
> + (match_operand 0 "memory_operand"))
> + (and (match_test "TARGET_X32")
> + (match_test "Pmode == DImode")
> + (match_operand 0 "GOT_memory_operand")))))
Also here.
> (define_constraint "Bz"
> "@internal Constant call address operand."
> diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
> index 117f6f6f7eb..7a2df43e7cd 100644
> --- a/gcc/config/i386/i386-expand.cc
> +++ b/gcc/config/i386/i386-expand.cc
> @@ -10225,13 +10225,21 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
> fnaddr = gen_rtx_MEM (QImode, construct_plt_address (XEXP (fnaddr, 0)));
> /* Since x32 GOT slot is 64 bit with zero upper 32 bits, indirect
> branch via x32 GOT slot is OK. */
> - else if (!(TARGET_X32
> - && MEM_P (fnaddr)
> - && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
> - && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode))
> - && (sibcall
> - ? !sibcall_insn_operand (XEXP (fnaddr, 0), word_mode)
> - : !call_insn_operand (XEXP (fnaddr, 0), word_mode)))
> + if (TARGET_X32
Please keep "else if" here. construct_plt_address always returns REG,
which is universally accepted as a call operand.
> + && MEM_P (fnaddr)
> + && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
> + && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode))
The purpose of this condition is to bypass the "else if" below. If you
write it as:
else if (TARGET_X32
&& MEM_P (fnaddr)
&& GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
&& GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode)
&& !TARGET_INDIRECT_BRANCH_REGISTER)
;
else if (sibcall ...
Then bypass won't be active, and "else if (sibcall ...)" will trigger,
copying the address to the register in the exact same way as your
newly added code.
> + {
> + fnaddr = convert_to_mode (word_mode, XEXP (fnaddr, 0), 1);
> + fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (word_mode,
> + fnaddr));
> + }
> + }
> + else if (sibcall
> + ? !sibcall_insn_operand (XEXP (fnaddr, 0), word_mode)
> + : !call_insn_operand (XEXP (fnaddr, 0), word_mode))
> {
> fnaddr = convert_to_mode (word_mode, XEXP (fnaddr, 0), 1);
> fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (word_mode, fnaddr));
> diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
> index f122fd8a0a3..bea3fd4b2e2 100644
> --- a/gcc/config/i386/i386-protos.h
> +++ b/gcc/config/i386/i386-protos.h
> @@ -371,6 +371,7 @@ extern int asm_preferred_eh_data_format (int, int);
> extern enum attr_cpu ix86_schedule;
> #endif
>
> +extern bool ix86_nopic_noplt_attribute_p (rtx call_op);
> extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
> extern const char * ix86_output_indirect_jmp (rtx call_op);
> extern const char * ix86_output_function_return (bool long_p);
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index 11770aa8a50..f89201684a8 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -16724,7 +16724,7 @@ ix86_ifunc_ref_local_ok (void)
> This is currently used only with 64-bit or 32-bit GOT32X ELF targets
> to call the function marked "noplt" indirectly. */
>
> -static bool
> +bool
> ix86_nopic_noplt_attribute_p (rtx call_op)
> {
> if (flag_pic || ix86_cmodel == CM_LARGE
> diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
> index 52c02b6351a..d6ae3ee378a 100644
> --- a/gcc/config/i386/i386.md
> +++ b/gcc/config/i386/i386.md
> @@ -20133,7 +20133,7 @@ (define_insn "*call_got_x32"
> [(call (mem:QI (zero_extend:DI
> (match_operand:SI 0 "GOT_memory_operand" "Bg")))
> (match_operand 1))]
> - "TARGET_X32"
> + "TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
> {
> rtx fnaddr = gen_const_mem (DImode, XEXP (operands[0], 0));
> return ix86_output_call_insn (insn, fnaddr);
> @@ -20338,7 +20338,7 @@ (define_insn "*call_value_got_x32"
> (zero_extend:DI
> (match_operand:SI 1 "GOT_memory_operand" "Bg")))
> (match_operand 2)))]
> - "TARGET_X32"
> + "TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
> {
> rtx fnaddr = gen_const_mem (DImode, XEXP (operands[1], 0));
> return ix86_output_call_insn (insn, fnaddr);
> @@ -20460,7 +20460,7 @@ (define_insn "*sibcall_value_pop_memory"
> (plus:SI (reg:SI SP_REG)
> (match_operand:SI 3 "immediate_operand" "i")))
> (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
> - "!TARGET_64BIT"
> + "!TARGET_64BIT && !TARGET_INDIRECT_BRANCH_REGISTER"
> "* return ix86_output_call_insn (insn, operands[1]);"
> [(set_attr "type" "callv")])
>
> diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
> index e733a474f9e..9a9101ed374 100644
> --- a/gcc/config/i386/predicates.md
> +++ b/gcc/config/i386/predicates.md
> @@ -670,7 +670,9 @@ (define_predicate "constant_call_address_operand"
> (match_code "symbol_ref")
> {
> if (ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC
> - || flag_force_indirect_call)
> + || flag_force_indirect_call
> + || (TARGET_INDIRECT_BRANCH_REGISTER
> + && ix86_nopic_noplt_attribute_p (op)))
> return false;
> if (TARGET_DLLIMPORT_DECL_ATTRIBUTES && SYMBOL_REF_DLLIMPORT_P (op))
> return false;
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-1-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-1-x32.c
> new file mode 100644
> index 00000000000..c27ac93ae87
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-1-x32.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fpic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-1.c"
> +
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
> +/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-1.c b/gcc/testsuite/gcc.target/i386/pr118713-1.c
> new file mode 100644
> index 00000000000..56884f3d952
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch-register" } */
> +
> +extern void bar (void);
> +
> +void
> +foo (void)
> +{
> + bar ();
> +}
> +
> +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT\\(" { target ia32 } } } */
> +/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-10-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-10-x32.c
> new file mode 100644
> index 00000000000..30d25ad6d0e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-10-x32.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-10.c"
> +
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
> +/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-10.c b/gcc/testsuite/gcc.target/i386/pr118713-10.c
> new file mode 100644
> index 00000000000..a0e2ff3760b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-10.c
> @@ -0,0 +1,15 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +extern void bar (void);
> +
> +int
> +foo (void)
> +{
> + bar ();
> + return 0;
> +}
> +
> +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT, " { target ia32 } } } */
> +/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-11-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-11-x32.c
> new file mode 100644
> index 00000000000..98afe50f42c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-11-x32.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-11.c"
> +
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
> +/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-11.c b/gcc/testsuite/gcc.target/i386/pr118713-11.c
> new file mode 100644
> index 00000000000..deb0c0df3c7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-11.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +extern int bar (void);
> +
> +int
> +foo (void)
> +{
> + return bar ();
> +}
> +
> +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT, " { target ia32 } } } */
> +/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-12-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-12-x32.c
> new file mode 100644
> index 00000000000..534ddab2344
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-12-x32.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-12.c"
> +
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
> +/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-12.c b/gcc/testsuite/gcc.target/i386/pr118713-12.c
> new file mode 100644
> index 00000000000..333b9c813e5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-12.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +extern int bar (void);
> +
> +int
> +foo (void)
> +{
> + return bar () + 1;
> +}
> +
> +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT, " { target ia32 } } } */
> +/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-2-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-2-x32.c
> new file mode 100644
> index 00000000000..4af932e68ed
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-2-x32.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fpic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-2.c"
> +
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
> +/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-2.c b/gcc/testsuite/gcc.target/i386/pr118713-2.c
> new file mode 100644
> index 00000000000..807724e0310
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-2.c
> @@ -0,0 +1,15 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch-register" } */
> +
> +extern void bar (void);
> +
> +int
> +foo (void)
> +{
> + bar ();
> + return 0;
> +}
> +
> +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT\\(" { target ia32 } } } */
> +/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-3-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-3-x32.c
> new file mode 100644
> index 00000000000..90a0e66a10c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-3-x32.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fpic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-3.c"
> +
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
> +/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-3.c b/gcc/testsuite/gcc.target/i386/pr118713-3.c
> new file mode 100644
> index 00000000000..1cd3fcbdf66
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch-register" } */
> +
> +extern int bar (void);
> +
> +int
> +foo (void)
> +{
> + return bar ();
> +}
> +
> +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT\\(" { target ia32 } } } */
> +/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-4-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-4-x32.c
> new file mode 100644
> index 00000000000..7f02f6003ea
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-4-x32.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fpic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-4.c"
> +
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
> +/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-4.c b/gcc/testsuite/gcc.target/i386/pr118713-4.c
> new file mode 100644
> index 00000000000..86d13b73bfc
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-4.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch-register" } */
> +
> +extern int bar (void);
> +
> +int
> +foo (void)
> +{
> + return bar () + 1;
> +}
> +
> +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT\\(" { target ia32 } } } */
> +/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-5-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-5-x32.c
> new file mode 100644
> index 00000000000..4642ace9d6a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-5-x32.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-5.c"
> +
> +/* { dg-final { scan-assembler "jmp\[ \t\]*bar" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-5.c b/gcc/testsuite/gcc.target/i386/pr118713-5.c
> new file mode 100644
> index 00000000000..0f44ab23c9b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-5.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +extern void bar (void) __attribute__((visibility("hidden")));
> +
> +void
> +foo (void)
> +{
> + bar ();
> +}
> +
> +/* { dg-final { scan-assembler "jmp\[ \t\]*bar" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-6-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-6-x32.c
> new file mode 100644
> index 00000000000..e7a2f35d569
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-6-x32.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-6.c"
> +
> +/* { dg-final { scan-assembler "call\[ \t\]*bar" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-6.c b/gcc/testsuite/gcc.target/i386/pr118713-6.c
> new file mode 100644
> index 00000000000..befe0b07e06
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-6.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +extern void bar (void) __attribute__((visibility("hidden")));
> +
> +int
> +foo (void)
> +{
> + bar ();
> + return 0;
> +}
> +
> +/* { dg-final { scan-assembler "call\[ \t\]*bar" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-7-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-7-x32.c
> new file mode 100644
> index 00000000000..35e9de5c187
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-7-x32.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-7.c"
> +
> +/* { dg-final { scan-assembler "jmp\[ \t\]*bar" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-7.c b/gcc/testsuite/gcc.target/i386/pr118713-7.c
> new file mode 100644
> index 00000000000..ba405be4272
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-7.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +extern int bar (void) __attribute__((visibility("hidden")));
> +
> +int
> +foo (void)
> +{
> + return bar ();
> +}
> +
> +/* { dg-final { scan-assembler "jmp\[ \t\]*bar" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-8-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-8-x32.c
> new file mode 100644
> index 00000000000..9aebe6aef64
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-8-x32.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-8.c"
> +
> +/* { dg-final { scan-assembler "call\[ \t\]*bar" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-8.c b/gcc/testsuite/gcc.target/i386/pr118713-8.c
> new file mode 100644
> index 00000000000..046f107a6f5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-8.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +extern int bar (void) __attribute__((visibility("hidden")));
> +
> +int
> +foo (void)
> +{
> + return bar () + 1;
> +}
> +
> +/* { dg-final { scan-assembler "call\[ \t\]*bar" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-9-x32.c b/gcc/testsuite/gcc.target/i386/pr118713-9-x32.c
> new file mode 100644
> index 00000000000..85819aa3380
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-9-x32.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-require-effective-target maybe_x32 } */
> +/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +#include "pr118713-9.c"
> +
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
> +/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr118713-9.c b/gcc/testsuite/gcc.target/i386/pr118713-9.c
> new file mode 100644
> index 00000000000..365f65fb194
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr118713-9.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
> +
> +extern void bar (void);
> +
> +void
> +foo (void)
> +{
> + bar ();
> +}
> +
> +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
> +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT, " { target ia32 } } } */
> +/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
> --
> 2.48.1
>
On Sat, Feb 1, 2025 at 5:52 PM Uros Bizjak <ubizjak@gmail.com> wrote:
>
> On Sat, Feb 1, 2025 at 9:51 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > If TARGET_INDIRECT_BRANCH_REGISTER is true, indirect call and jump should
> > use register, not memory. Update Bs, Bw and Bz constraints to disable
> > indirect call over memmory if TARGET_INDIRECT_BRANCH_REGISTER true, change
> > x32 call over GOT slot to call over register and also disable sibcall
> > over memory.
> >
> > gcc/
> >
> > PR target/118713
> > * config/i386/constraints.md (Bs): Always disable if
> > TARGET_INDIRECT_BRANCH_REGISTER is true.
> > (Bw): Likewise.
> > * config/i386/i386-expand.cc (ix86_expand_call): Force indirect
> > call via register for GOT slot call if
> > TARGET_INDIRECT_BRANCH_REGISTER is true.
> > * config/i386/i386-protos.h (ix86_nopic_noplt_attribute_p): New.
> > * config/i386/i386.cc (ix86_nopic_noplt_attribute_p): Make it
> > global.
> > * config/i386/i386.md (*call_got_x32): Disable indirect call via
> > memory for TARGET_INDIRECT_BRANCH_REGISTER.
> > (*call_value_got_x32): Likewise.
> > (*sibcall_value_pop_memory): Likewise.
> > * config/i386/predicates.md (constant_call_address_operand):
> > Return false if both TARGET_INDIRECT_BRANCH_REGISTER and
> > ix86_nopic_noplt_attribute_p are true.
>
> LGTM, with some code reshuffling, proposed below. I didn't do a
> thorough review on how T_I_B_R is handled, you are the expert in the
> area of symbol handling.
>
> Thanks,
> Uros.
>
> >
> > gcc/testsuite/
> >
> > PR target/118713
> > * gcc.target/i386/pr118713-1-x32.c: New test.
> > * gcc.target/i386/pr118713-1.c: Likewise.
> > * gcc.target/i386/pr118713-2-x32.c: Likewise.
> > * gcc.target/i386/pr118713-2.c: Likewise.
> > * gcc.target/i386/pr118713-3-x32.c: Likewise.
> > * gcc.target/i386/pr118713-3.c: Likewise.
> > * gcc.target/i386/pr118713-4-x32.c: Likewise.
> > * gcc.target/i386/pr118713-4.c: Likewise.
> > * gcc.target/i386/pr118713-5-x32.c: Likewise.
> > * gcc.target/i386/pr118713-5.c: Likewise.
> > * gcc.target/i386/pr118713-6-x32.c: Likewise.
> > * gcc.target/i386/pr118713-6.c: Likewise.
> > * gcc.target/i386/pr118713-7-x32.c: Likewise.
> > * gcc.target/i386/pr118713-7.c: Likewise.
> > * gcc.target/i386/pr118713-8-x32.c: Likewise.
> > * gcc.target/i386/pr118713-8.c: Likewise.
> > * gcc.target/i386/pr118713-9-x32.c: Likewise.
> > * gcc.target/i386/pr118713-9.c: Likewise.
> > * gcc.target/i386/pr118713-10-x32.c: Likewise.
> > * gcc.target/i386/pr118713-10.c: Likewise.
> > * gcc.target/i386/pr118713-11-x32.c: Likewise.
> > * gcc.target/i386/pr118713-11.c: Likewise.
> > * gcc.target/i386/pr118713-12-x32.c: Likewise.
> > * gcc.target/i386/pr118713-12.c: Likewise.
> >
> > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > ---
> > gcc/config/i386/constraints.md | 24 +++++++++----------
> > gcc/config/i386/i386-expand.cc | 22 +++++++++++------
> > gcc/config/i386/i386-protos.h | 1 +
> > gcc/config/i386/i386.cc | 2 +-
> > gcc/config/i386/i386.md | 6 ++---
> > gcc/config/i386/predicates.md | 4 +++-
> > .../gcc.target/i386/pr118713-1-x32.c | 8 +++++++
> > gcc/testsuite/gcc.target/i386/pr118713-1.c | 14 +++++++++++
> > .../gcc.target/i386/pr118713-10-x32.c | 8 +++++++
> > gcc/testsuite/gcc.target/i386/pr118713-10.c | 15 ++++++++++++
> > .../gcc.target/i386/pr118713-11-x32.c | 8 +++++++
> > gcc/testsuite/gcc.target/i386/pr118713-11.c | 14 +++++++++++
> > .../gcc.target/i386/pr118713-12-x32.c | 8 +++++++
> > gcc/testsuite/gcc.target/i386/pr118713-12.c | 14 +++++++++++
> > .../gcc.target/i386/pr118713-2-x32.c | 8 +++++++
> > gcc/testsuite/gcc.target/i386/pr118713-2.c | 15 ++++++++++++
> > .../gcc.target/i386/pr118713-3-x32.c | 8 +++++++
> > gcc/testsuite/gcc.target/i386/pr118713-3.c | 14 +++++++++++
> > .../gcc.target/i386/pr118713-4-x32.c | 8 +++++++
> > gcc/testsuite/gcc.target/i386/pr118713-4.c | 14 +++++++++++
> > .../gcc.target/i386/pr118713-5-x32.c | 7 ++++++
> > gcc/testsuite/gcc.target/i386/pr118713-5.c | 12 ++++++++++
> > .../gcc.target/i386/pr118713-6-x32.c | 7 ++++++
> > gcc/testsuite/gcc.target/i386/pr118713-6.c | 13 ++++++++++
> > .../gcc.target/i386/pr118713-7-x32.c | 7 ++++++
> > gcc/testsuite/gcc.target/i386/pr118713-7.c | 12 ++++++++++
> > .../gcc.target/i386/pr118713-8-x32.c | 7 ++++++
> > gcc/testsuite/gcc.target/i386/pr118713-8.c | 12 ++++++++++
> > .../gcc.target/i386/pr118713-9-x32.c | 8 +++++++
> > gcc/testsuite/gcc.target/i386/pr118713-9.c | 14 +++++++++++
> > 30 files changed, 290 insertions(+), 24 deletions(-)
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-1-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-1.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-10-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-10.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-11-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-11.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-12-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-12.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-2-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-2.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-3-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-3.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-4-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-4.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-5-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-5.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-6-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-6.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-7-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-7.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-8-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-8.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-9-x32.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-9.c
> >
> > diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
> > index 9dd280568bd..d3d6e9e66f4 100644
> > --- a/gcc/config/i386/constraints.md
> > +++ b/gcc/config/i386/constraints.md
> > @@ -203,21 +203,21 @@ (define_special_memory_constraint "Br"
> >
> > (define_constraint "Bs"
> > "@internal Sibcall memory operand."
> > - (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
> > - (not (match_test "TARGET_X32"))
> > - (match_operand 0 "sibcall_memory_operand"))
> > - (and (match_test "TARGET_X32")
> > - (match_test "Pmode == DImode")
> > - (match_operand 0 "GOT_memory_operand"))))
> > + (and (match_test "!TARGET_INDIRECT_BRANCH_REGISTER")
> > + (ior (and (match_test "!TARGET_X32")
> > + (match_operand 0 "sibcall_memory_operand"))
> > + (and (match_test "TARGET_X32")
> > + (match_test "Pmode == DImode")
> > + (match_operand 0 "GOT_memory_operand")))))
>
> While here, the above can use if_then_else RTX (and not RTX for
> consistency), like:
>
> (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
> (if_then_else (match_test "TARGET_X32")
> (and (match_test "Pmode == DImode")
> (match_operand 0 "GOT_memory_operand"))
> (match_operand 0 "sibcall_memory_operand")))
Will fix it.
> > (define_constraint "Bw"
> > "@internal Call memory operand."
> > - (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
> > - (not (match_test "TARGET_X32"))
> > - (match_operand 0 "memory_operand"))
> > - (and (match_test "TARGET_X32")
> > - (match_test "Pmode == DImode")
> > - (match_operand 0 "GOT_memory_operand"))))
> > + (and (match_test "!TARGET_INDIRECT_BRANCH_REGISTER")
> > + (ior (and (match_test "!TARGET_X32")
> > + (match_operand 0 "memory_operand"))
> > + (and (match_test "TARGET_X32")
> > + (match_test "Pmode == DImode")
> > + (match_operand 0 "GOT_memory_operand")))))
>
> Also here.
Will fix it.
>
> > (define_constraint "Bz"
> > "@internal Constant call address operand."
> > diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
> > index 117f6f6f7eb..7a2df43e7cd 100644
> > --- a/gcc/config/i386/i386-expand.cc
> > +++ b/gcc/config/i386/i386-expand.cc
> > @@ -10225,13 +10225,21 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
> > fnaddr = gen_rtx_MEM (QImode, construct_plt_address (XEXP (fnaddr, 0)));
> > /* Since x32 GOT slot is 64 bit with zero upper 32 bits, indirect
> > branch via x32 GOT slot is OK. */
> > - else if (!(TARGET_X32
> > - && MEM_P (fnaddr)
> > - && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
> > - && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode))
> > - && (sibcall
> > - ? !sibcall_insn_operand (XEXP (fnaddr, 0), word_mode)
> > - : !call_insn_operand (XEXP (fnaddr, 0), word_mode)))
> > + if (TARGET_X32
>
> Please keep "else if" here. construct_plt_address always returns REG,
> which is universally accepted as a call operand.
>
> > + && MEM_P (fnaddr)
> > + && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
> > + && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode))
>
> The purpose of this condition is to bypass the "else if" below. If you
> write it as:
>
> else if (TARGET_X32
> && MEM_P (fnaddr)
> && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
> && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode)
> && !TARGET_INDIRECT_BRANCH_REGISTER)
> ;
> else if (sibcall ...
>
> Then bypass won't be active, and "else if (sibcall ...)" will trigger,
> copying the address to the register in the exact same way as your
> newly added code.
Will fix it.
>
> > + {
> > + fnaddr = convert_to_mode (word_mode, XEXP (fnaddr, 0), 1);
> > + fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (word_mode,
> > + fnaddr));
> > + }
> > + }
> > + else if (sibcall
> > + ? !sibcall_insn_operand (XEXP (fnaddr, 0), word_mode)
> > + : !call_insn_operand (XEXP (fnaddr, 0), word_mode))
> > {
> > fnaddr = convert_to_mode (word_mode, XEXP (fnaddr, 0), 1);
> > fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (word_mode, fnaddr));
> > diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
> > index f122fd8a0a3..bea3fd4b2e2 100644
> > --- a/gcc/config/i386/i386-protos.h
> > +++ b/gcc/config/i386/i386-protos.h
> > @@ -371,6 +371,7 @@ extern int asm_preferred_eh_data_format (int, int);
> > extern enum attr_cpu ix86_schedule;
> > #endif
> >
> > +extern bool ix86_nopic_noplt_attribute_p (rtx call_op);
> > extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
> > extern const char * ix86_output_indirect_jmp (rtx call_op);
> > extern const char * ix86_output_function_return (bool long_p);
> > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> > index 11770aa8a50..f89201684a8 100644
> > --- a/gcc/config/i386/i386.cc
> > +++ b/gcc/config/i386/i386.cc
> > @@ -16724,7 +16724,7 @@ ix86_ifunc_ref_local_ok (void)
> > This is currently used only with 64-bit or 32-bit GOT32X ELF targets
> > to call the function marked "noplt" indirectly. */
> >
> > -static bool
> > +bool
> > ix86_nopic_noplt_attribute_p (rtx call_op)
> > {
> > if (flag_pic || ix86_cmodel == CM_LARGE
> > diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
> > index 52c02b6351a..d6ae3ee378a 100644
> > --- a/gcc/config/i386/i386.md
> > +++ b/gcc/config/i386/i386.md
> > @@ -20133,7 +20133,7 @@ (define_insn "*call_got_x32"
> > [(call (mem:QI (zero_extend:DI
> > (match_operand:SI 0 "GOT_memory_operand" "Bg")))
> > (match_operand 1))]
> > - "TARGET_X32"
> > + "TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
> > {
> > rtx fnaddr = gen_const_mem (DImode, XEXP (operands[0], 0));
> > return ix86_output_call_insn (insn, fnaddr);
> > @@ -20338,7 +20338,7 @@ (define_insn "*call_value_got_x32"
> > (zero_extend:DI
> > (match_operand:SI 1 "GOT_memory_operand" "Bg")))
> > (match_operand 2)))]
> > - "TARGET_X32"
> > + "TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
> > {
> > rtx fnaddr = gen_const_mem (DImode, XEXP (operands[1], 0));
> > return ix86_output_call_insn (insn, fnaddr);
> > @@ -20460,7 +20460,7 @@ (define_insn "*sibcall_value_pop_memory"
> > (plus:SI (reg:SI SP_REG)
> > (match_operand:SI 3 "immediate_operand" "i")))
> > (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
> > - "!TARGET_64BIT"
> > + "!TARGET_64BIT && !TARGET_INDIRECT_BRANCH_REGISTER"
> > "* return ix86_output_call_insn (insn, operands[1]);"
> > [(set_attr "type" "callv")])
> >
> > diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
> > index e733a474f9e..9a9101ed374 100644
> > --- a/gcc/config/i386/predicates.md
> > +++ b/gcc/config/i386/predicates.md
> > @@ -670,7 +670,9 @@ (define_predicate "constant_call_address_operand"
> > (match_code "symbol_ref")
> > {
> > if (ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC
> > - || flag_force_indirect_call)
> > + || flag_force_indirect_call
> > + || (TARGET_INDIRECT_BRANCH_REGISTER
> > + && ix86_nopic_noplt_attribute_p (op)))
> > return false;
> > if (TARGET_DLLIMPORT_DECL_ATTRIBUTES && SYMBOL_REF_DLLIMPORT_P (op))
> > return false;
This is the patch I am testing.
Thanks.
On Sat, Feb 1, 2025 at 6:33 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Sat, Feb 1, 2025 at 5:52 PM Uros Bizjak <ubizjak@gmail.com> wrote:
> >
> > On Sat, Feb 1, 2025 at 9:51 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > If TARGET_INDIRECT_BRANCH_REGISTER is true, indirect call and jump should
> > > use register, not memory. Update Bs, Bw and Bz constraints to disable
> > > indirect call over memmory if TARGET_INDIRECT_BRANCH_REGISTER true, change
> > > x32 call over GOT slot to call over register and also disable sibcall
> > > over memory.
> > >
> > > gcc/
> > >
> > > PR target/118713
> > > * config/i386/constraints.md (Bs): Always disable if
> > > TARGET_INDIRECT_BRANCH_REGISTER is true.
> > > (Bw): Likewise.
> > > * config/i386/i386-expand.cc (ix86_expand_call): Force indirect
> > > call via register for GOT slot call if
> > > TARGET_INDIRECT_BRANCH_REGISTER is true.
> > > * config/i386/i386-protos.h (ix86_nopic_noplt_attribute_p): New.
> > > * config/i386/i386.cc (ix86_nopic_noplt_attribute_p): Make it
> > > global.
> > > * config/i386/i386.md (*call_got_x32): Disable indirect call via
> > > memory for TARGET_INDIRECT_BRANCH_REGISTER.
> > > (*call_value_got_x32): Likewise.
> > > (*sibcall_value_pop_memory): Likewise.
> > > * config/i386/predicates.md (constant_call_address_operand):
> > > Return false if both TARGET_INDIRECT_BRANCH_REGISTER and
> > > ix86_nopic_noplt_attribute_p are true.
> >
> > LGTM, with some code reshuffling, proposed below. I didn't do a
> > thorough review on how T_I_B_R is handled, you are the expert in the
> > area of symbol handling.
> >
> > Thanks,
> > Uros.
> >
> > >
> > > gcc/testsuite/
> > >
> > > PR target/118713
> > > * gcc.target/i386/pr118713-1-x32.c: New test.
> > > * gcc.target/i386/pr118713-1.c: Likewise.
> > > * gcc.target/i386/pr118713-2-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-2.c: Likewise.
> > > * gcc.target/i386/pr118713-3-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-3.c: Likewise.
> > > * gcc.target/i386/pr118713-4-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-4.c: Likewise.
> > > * gcc.target/i386/pr118713-5-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-5.c: Likewise.
> > > * gcc.target/i386/pr118713-6-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-6.c: Likewise.
> > > * gcc.target/i386/pr118713-7-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-7.c: Likewise.
> > > * gcc.target/i386/pr118713-8-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-8.c: Likewise.
> > > * gcc.target/i386/pr118713-9-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-9.c: Likewise.
> > > * gcc.target/i386/pr118713-10-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-10.c: Likewise.
> > > * gcc.target/i386/pr118713-11-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-11.c: Likewise.
> > > * gcc.target/i386/pr118713-12-x32.c: Likewise.
> > > * gcc.target/i386/pr118713-12.c: Likewise.
> > >
> > > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > > ---
> > > gcc/config/i386/constraints.md | 24 +++++++++----------
> > > gcc/config/i386/i386-expand.cc | 22 +++++++++++------
> > > gcc/config/i386/i386-protos.h | 1 +
> > > gcc/config/i386/i386.cc | 2 +-
> > > gcc/config/i386/i386.md | 6 ++---
> > > gcc/config/i386/predicates.md | 4 +++-
> > > .../gcc.target/i386/pr118713-1-x32.c | 8 +++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-1.c | 14 +++++++++++
> > > .../gcc.target/i386/pr118713-10-x32.c | 8 +++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-10.c | 15 ++++++++++++
> > > .../gcc.target/i386/pr118713-11-x32.c | 8 +++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-11.c | 14 +++++++++++
> > > .../gcc.target/i386/pr118713-12-x32.c | 8 +++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-12.c | 14 +++++++++++
> > > .../gcc.target/i386/pr118713-2-x32.c | 8 +++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-2.c | 15 ++++++++++++
> > > .../gcc.target/i386/pr118713-3-x32.c | 8 +++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-3.c | 14 +++++++++++
> > > .../gcc.target/i386/pr118713-4-x32.c | 8 +++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-4.c | 14 +++++++++++
> > > .../gcc.target/i386/pr118713-5-x32.c | 7 ++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-5.c | 12 ++++++++++
> > > .../gcc.target/i386/pr118713-6-x32.c | 7 ++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-6.c | 13 ++++++++++
> > > .../gcc.target/i386/pr118713-7-x32.c | 7 ++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-7.c | 12 ++++++++++
> > > .../gcc.target/i386/pr118713-8-x32.c | 7 ++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-8.c | 12 ++++++++++
> > > .../gcc.target/i386/pr118713-9-x32.c | 8 +++++++
> > > gcc/testsuite/gcc.target/i386/pr118713-9.c | 14 +++++++++++
> > > 30 files changed, 290 insertions(+), 24 deletions(-)
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-1-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-1.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-10-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-10.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-11-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-11.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-12-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-12.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-2-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-2.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-3-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-3.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-4-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-4.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-5-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-5.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-6-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-6.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-7-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-7.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-8-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-8.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-9-x32.c
> > > create mode 100644 gcc/testsuite/gcc.target/i386/pr118713-9.c
> > >
> > > diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
> > > index 9dd280568bd..d3d6e9e66f4 100644
> > > --- a/gcc/config/i386/constraints.md
> > > +++ b/gcc/config/i386/constraints.md
> > > @@ -203,21 +203,21 @@ (define_special_memory_constraint "Br"
> > >
> > > (define_constraint "Bs"
> > > "@internal Sibcall memory operand."
> > > - (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
> > > - (not (match_test "TARGET_X32"))
> > > - (match_operand 0 "sibcall_memory_operand"))
> > > - (and (match_test "TARGET_X32")
> > > - (match_test "Pmode == DImode")
> > > - (match_operand 0 "GOT_memory_operand"))))
> > > + (and (match_test "!TARGET_INDIRECT_BRANCH_REGISTER")
> > > + (ior (and (match_test "!TARGET_X32")
> > > + (match_operand 0 "sibcall_memory_operand"))
> > > + (and (match_test "TARGET_X32")
> > > + (match_test "Pmode == DImode")
> > > + (match_operand 0 "GOT_memory_operand")))))
> >
> > While here, the above can use if_then_else RTX (and not RTX for
> > consistency), like:
> >
> > (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
> > (if_then_else (match_test "TARGET_X32")
> > (and (match_test "Pmode == DImode")
> > (match_operand 0 "GOT_memory_operand"))
> > (match_operand 0 "sibcall_memory_operand")))
>
> Will fix it.
>
> > > (define_constraint "Bw"
> > > "@internal Call memory operand."
> > > - (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
> > > - (not (match_test "TARGET_X32"))
> > > - (match_operand 0 "memory_operand"))
> > > - (and (match_test "TARGET_X32")
> > > - (match_test "Pmode == DImode")
> > > - (match_operand 0 "GOT_memory_operand"))))
> > > + (and (match_test "!TARGET_INDIRECT_BRANCH_REGISTER")
> > > + (ior (and (match_test "!TARGET_X32")
> > > + (match_operand 0 "memory_operand"))
> > > + (and (match_test "TARGET_X32")
> > > + (match_test "Pmode == DImode")
> > > + (match_operand 0 "GOT_memory_operand")))))
> >
> > Also here.
>
> Will fix it.
>
> >
> > > (define_constraint "Bz"
> > > "@internal Constant call address operand."
> > > diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
> > > index 117f6f6f7eb..7a2df43e7cd 100644
> > > --- a/gcc/config/i386/i386-expand.cc
> > > +++ b/gcc/config/i386/i386-expand.cc
> > > @@ -10225,13 +10225,21 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
> > > fnaddr = gen_rtx_MEM (QImode, construct_plt_address (XEXP (fnaddr, 0)));
> > > /* Since x32 GOT slot is 64 bit with zero upper 32 bits, indirect
> > > branch via x32 GOT slot is OK. */
> > > - else if (!(TARGET_X32
> > > - && MEM_P (fnaddr)
> > > - && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
> > > - && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode))
> > > - && (sibcall
> > > - ? !sibcall_insn_operand (XEXP (fnaddr, 0), word_mode)
> > > - : !call_insn_operand (XEXP (fnaddr, 0), word_mode)))
> > > + if (TARGET_X32
> >
> > Please keep "else if" here. construct_plt_address always returns REG,
> > which is universally accepted as a call operand.
> >
> > > + && MEM_P (fnaddr)
> > > + && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
> > > + && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode))
> >
> > The purpose of this condition is to bypass the "else if" below. If you
> > write it as:
> >
> > else if (TARGET_X32
> > && MEM_P (fnaddr)
> > && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
> > && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode)
> > && !TARGET_INDIRECT_BRANCH_REGISTER)
> > ;
> > else if (sibcall ...
> >
> > Then bypass won't be active, and "else if (sibcall ...)" will trigger,
> > copying the address to the register in the exact same way as your
> > newly added code.
>
> Will fix it.
>
> >
> > > + {
> > > + fnaddr = convert_to_mode (word_mode, XEXP (fnaddr, 0), 1);
> > > + fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (word_mode,
> > > + fnaddr));
> > > + }
> > > + }
> > > + else if (sibcall
> > > + ? !sibcall_insn_operand (XEXP (fnaddr, 0), word_mode)
> > > + : !call_insn_operand (XEXP (fnaddr, 0), word_mode))
> > > {
> > > fnaddr = convert_to_mode (word_mode, XEXP (fnaddr, 0), 1);
> > > fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (word_mode, fnaddr));
> > > diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
> > > index f122fd8a0a3..bea3fd4b2e2 100644
> > > --- a/gcc/config/i386/i386-protos.h
> > > +++ b/gcc/config/i386/i386-protos.h
> > > @@ -371,6 +371,7 @@ extern int asm_preferred_eh_data_format (int, int);
> > > extern enum attr_cpu ix86_schedule;
> > > #endif
> > >
> > > +extern bool ix86_nopic_noplt_attribute_p (rtx call_op);
> > > extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
> > > extern const char * ix86_output_indirect_jmp (rtx call_op);
> > > extern const char * ix86_output_function_return (bool long_p);
> > > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> > > index 11770aa8a50..f89201684a8 100644
> > > --- a/gcc/config/i386/i386.cc
> > > +++ b/gcc/config/i386/i386.cc
> > > @@ -16724,7 +16724,7 @@ ix86_ifunc_ref_local_ok (void)
> > > This is currently used only with 64-bit or 32-bit GOT32X ELF targets
> > > to call the function marked "noplt" indirectly. */
> > >
> > > -static bool
> > > +bool
> > > ix86_nopic_noplt_attribute_p (rtx call_op)
> > > {
> > > if (flag_pic || ix86_cmodel == CM_LARGE
> > > diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
> > > index 52c02b6351a..d6ae3ee378a 100644
> > > --- a/gcc/config/i386/i386.md
> > > +++ b/gcc/config/i386/i386.md
> > > @@ -20133,7 +20133,7 @@ (define_insn "*call_got_x32"
> > > [(call (mem:QI (zero_extend:DI
> > > (match_operand:SI 0 "GOT_memory_operand" "Bg")))
> > > (match_operand 1))]
> > > - "TARGET_X32"
> > > + "TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
> > > {
> > > rtx fnaddr = gen_const_mem (DImode, XEXP (operands[0], 0));
> > > return ix86_output_call_insn (insn, fnaddr);
> > > @@ -20338,7 +20338,7 @@ (define_insn "*call_value_got_x32"
> > > (zero_extend:DI
> > > (match_operand:SI 1 "GOT_memory_operand" "Bg")))
> > > (match_operand 2)))]
> > > - "TARGET_X32"
> > > + "TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
> > > {
> > > rtx fnaddr = gen_const_mem (DImode, XEXP (operands[1], 0));
> > > return ix86_output_call_insn (insn, fnaddr);
> > > @@ -20460,7 +20460,7 @@ (define_insn "*sibcall_value_pop_memory"
> > > (plus:SI (reg:SI SP_REG)
> > > (match_operand:SI 3 "immediate_operand" "i")))
> > > (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
> > > - "!TARGET_64BIT"
> > > + "!TARGET_64BIT && !TARGET_INDIRECT_BRANCH_REGISTER"
> > > "* return ix86_output_call_insn (insn, operands[1]);"
> > > [(set_attr "type" "callv")])
> > >
> > > diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
> > > index e733a474f9e..9a9101ed374 100644
> > > --- a/gcc/config/i386/predicates.md
> > > +++ b/gcc/config/i386/predicates.md
> > > @@ -670,7 +670,9 @@ (define_predicate "constant_call_address_operand"
> > > (match_code "symbol_ref")
> > > {
> > > if (ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC
> > > - || flag_force_indirect_call)
> > > + || flag_force_indirect_call
> > > + || (TARGET_INDIRECT_BRANCH_REGISTER
> > > + && ix86_nopic_noplt_attribute_p (op)))
> > > return false;
> > > if (TARGET_DLLIMPORT_DECL_ATTRIBUTES && SYMBOL_REF_DLLIMPORT_P (op))
> > > return false;
>
> This is the patch I am testing.
No regressions. I am checking it in.
Thanks.
@@ -203,21 +203,21 @@ (define_special_memory_constraint "Br"
(define_constraint "Bs"
"@internal Sibcall memory operand."
- (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
- (not (match_test "TARGET_X32"))
- (match_operand 0 "sibcall_memory_operand"))
- (and (match_test "TARGET_X32")
- (match_test "Pmode == DImode")
- (match_operand 0 "GOT_memory_operand"))))
+ (and (match_test "!TARGET_INDIRECT_BRANCH_REGISTER")
+ (ior (and (match_test "!TARGET_X32")
+ (match_operand 0 "sibcall_memory_operand"))
+ (and (match_test "TARGET_X32")
+ (match_test "Pmode == DImode")
+ (match_operand 0 "GOT_memory_operand")))))
(define_constraint "Bw"
"@internal Call memory operand."
- (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
- (not (match_test "TARGET_X32"))
- (match_operand 0 "memory_operand"))
- (and (match_test "TARGET_X32")
- (match_test "Pmode == DImode")
- (match_operand 0 "GOT_memory_operand"))))
+ (and (match_test "!TARGET_INDIRECT_BRANCH_REGISTER")
+ (ior (and (match_test "!TARGET_X32")
+ (match_operand 0 "memory_operand"))
+ (and (match_test "TARGET_X32")
+ (match_test "Pmode == DImode")
+ (match_operand 0 "GOT_memory_operand")))))
(define_constraint "Bz"
"@internal Constant call address operand."
@@ -10225,13 +10225,21 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
fnaddr = gen_rtx_MEM (QImode, construct_plt_address (XEXP (fnaddr, 0)));
/* Since x32 GOT slot is 64 bit with zero upper 32 bits, indirect
branch via x32 GOT slot is OK. */
- else if (!(TARGET_X32
- && MEM_P (fnaddr)
- && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
- && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode))
- && (sibcall
- ? !sibcall_insn_operand (XEXP (fnaddr, 0), word_mode)
- : !call_insn_operand (XEXP (fnaddr, 0), word_mode)))
+ if (TARGET_X32
+ && MEM_P (fnaddr)
+ && GET_CODE (XEXP (fnaddr, 0)) == ZERO_EXTEND
+ && GOT_memory_operand (XEXP (XEXP (fnaddr, 0), 0), Pmode))
+ {
+ if (TARGET_INDIRECT_BRANCH_REGISTER)
+ {
+ fnaddr = convert_to_mode (word_mode, XEXP (fnaddr, 0), 1);
+ fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (word_mode,
+ fnaddr));
+ }
+ }
+ else if (sibcall
+ ? !sibcall_insn_operand (XEXP (fnaddr, 0), word_mode)
+ : !call_insn_operand (XEXP (fnaddr, 0), word_mode))
{
fnaddr = convert_to_mode (word_mode, XEXP (fnaddr, 0), 1);
fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (word_mode, fnaddr));
@@ -371,6 +371,7 @@ extern int asm_preferred_eh_data_format (int, int);
extern enum attr_cpu ix86_schedule;
#endif
+extern bool ix86_nopic_noplt_attribute_p (rtx call_op);
extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
extern const char * ix86_output_indirect_jmp (rtx call_op);
extern const char * ix86_output_function_return (bool long_p);
@@ -16724,7 +16724,7 @@ ix86_ifunc_ref_local_ok (void)
This is currently used only with 64-bit or 32-bit GOT32X ELF targets
to call the function marked "noplt" indirectly. */
-static bool
+bool
ix86_nopic_noplt_attribute_p (rtx call_op)
{
if (flag_pic || ix86_cmodel == CM_LARGE
@@ -20133,7 +20133,7 @@ (define_insn "*call_got_x32"
[(call (mem:QI (zero_extend:DI
(match_operand:SI 0 "GOT_memory_operand" "Bg")))
(match_operand 1))]
- "TARGET_X32"
+ "TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
{
rtx fnaddr = gen_const_mem (DImode, XEXP (operands[0], 0));
return ix86_output_call_insn (insn, fnaddr);
@@ -20338,7 +20338,7 @@ (define_insn "*call_value_got_x32"
(zero_extend:DI
(match_operand:SI 1 "GOT_memory_operand" "Bg")))
(match_operand 2)))]
- "TARGET_X32"
+ "TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
{
rtx fnaddr = gen_const_mem (DImode, XEXP (operands[1], 0));
return ix86_output_call_insn (insn, fnaddr);
@@ -20460,7 +20460,7 @@ (define_insn "*sibcall_value_pop_memory"
(plus:SI (reg:SI SP_REG)
(match_operand:SI 3 "immediate_operand" "i")))
(unspec [(const_int 0)] UNSPEC_PEEPSIB)]
- "!TARGET_64BIT"
+ "!TARGET_64BIT && !TARGET_INDIRECT_BRANCH_REGISTER"
"* return ix86_output_call_insn (insn, operands[1]);"
[(set_attr "type" "callv")])
@@ -670,7 +670,9 @@ (define_predicate "constant_call_address_operand"
(match_code "symbol_ref")
{
if (ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC
- || flag_force_indirect_call)
+ || flag_force_indirect_call
+ || (TARGET_INDIRECT_BRANCH_REGISTER
+ && ix86_nopic_noplt_attribute_p (op)))
return false;
if (TARGET_DLLIMPORT_DECL_ATTRIBUTES && SYMBOL_REF_DLLIMPORT_P (op))
return false;
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fpic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-1.c"
+
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch-register" } */
+
+extern void bar (void);
+
+void
+foo (void)
+{
+ bar ();
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT\\(" { target ia32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-10.c"
+
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+extern void bar (void);
+
+int
+foo (void)
+{
+ bar ();
+ return 0;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT, " { target ia32 } } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-11.c"
+
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+extern int bar (void);
+
+int
+foo (void)
+{
+ return bar ();
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT, " { target ia32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-12.c"
+
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+extern int bar (void);
+
+int
+foo (void)
+{
+ return bar () + 1;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT, " { target ia32 } } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fpic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-2.c"
+
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch-register" } */
+
+extern void bar (void);
+
+int
+foo (void)
+{
+ bar ();
+ return 0;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT\\(" { target ia32 } } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fpic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-3.c"
+
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch-register" } */
+
+extern int bar (void);
+
+int
+foo (void)
+{
+ return bar ();
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT\\(" { target ia32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fpic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-4.c"
+
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch-register" } */
+
+extern int bar (void);
+
+int
+foo (void)
+{
+ return bar () + 1;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT\\(" { target ia32 } } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-5.c"
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*bar" } } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+extern void bar (void) __attribute__((visibility("hidden")));
+
+void
+foo (void)
+{
+ bar ();
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*bar" } } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-6.c"
+
+/* { dg-final { scan-assembler "call\[ \t\]*bar" } } */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+extern void bar (void) __attribute__((visibility("hidden")));
+
+int
+foo (void)
+{
+ bar ();
+ return 0;
+}
+
+/* { dg-final { scan-assembler "call\[ \t\]*bar" } } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-7.c"
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*bar" } } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+extern int bar (void) __attribute__((visibility("hidden")));
+
+int
+foo (void)
+{
+ return bar ();
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*bar" } } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-8.c"
+
+/* { dg-final { scan-assembler "call\[ \t\]*bar" } } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+extern int bar (void) __attribute__((visibility("hidden")));
+
+int
+foo (void)
+{
+ return bar () + 1;
+}
+
+/* { dg-final { scan-assembler "call\[ \t\]*bar" } } */
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+#include "pr118713-9.c"
+
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt -mindirect-branch-register" } */
+
+extern void bar (void);
+
+void
+foo (void)
+{
+ bar ();
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT, " { target ia32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\\*%" } } */