[v3] x86: Handle TARGET_INDIRECT_BRANCH_REGISTER for -fno-plt

Message ID 20250201085130.289644-1-hjl.tools@gmail.com
State New
Headers
Series [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

H.J. Lu Feb. 1, 2025, 8:51 a.m. UTC
  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

Uros Bizjak Feb. 1, 2025, 9:51 a.m. UTC | #1
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
>
  
H.J. Lu Feb. 1, 2025, 10:33 a.m. UTC | #2
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.
  
H.J. Lu Feb. 1, 2025, 1:45 p.m. UTC | #3
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.
  

Patch

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")))))
 
 (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."
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
+      && 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));
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\]*\\*%" } } */