aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2025-01-31 12:29:04 +0800
committerH.J. Lu <hjl.tools@gmail.com>2025-02-01 21:47:26 +0800
commitdd6247cb8fc11a15e23e949092f89d24ff329209 (patch)
tree61a0860e9bee20c8866aca41ceabbd12c514900c /gcc
parentcf24c0fa53870da6e666a97b79c4b053317c4951 (diff)
downloadgcc-dd6247cb8fc11a15e23e949092f89d24ff329209.zip
gcc-dd6247cb8fc11a15e23e949092f89d24ff329209.tar.gz
gcc-dd6247cb8fc11a15e23e949092f89d24ff329209.tar.bz2
x86: Handle TARGET_INDIRECT_BRANCH_REGISTER for -fno-plt
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 x32 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>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/i386/constraints.md22
-rw-r--r--gcc/config/i386/i386-expand.cc16
-rw-r--r--gcc/config/i386/i386-protos.h1
-rw-r--r--gcc/config/i386/i386.cc2
-rw-r--r--gcc/config/i386/i386.md6
-rw-r--r--gcc/config/i386/predicates.md4
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-1-x32.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-1.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-10-x32.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-10.c15
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-11-x32.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-11.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-12-x32.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-12.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-2-x32.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-2.c15
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-3-x32.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-3.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-4-x32.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-4.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-5-x32.c7
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-5.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-6-x32.c7
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-6.c13
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-7-x32.c7
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-7.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-8-x32.c7
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-8.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-9-x32.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr118713-9.c14
30 files changed, 282 insertions, 24 deletions
diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
index 9dd2805..38877a7 100644
--- a/gcc/config/i386/constraints.md
+++ b/gcc/config/i386/constraints.md
@@ -203,21 +203,19 @@
(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 (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 (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 "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 117f6f6..a43b0f0 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -10225,13 +10225,15 @@ 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)
+ && !TARGET_INDIRECT_BRANCH_REGISTER)
+ ;
+ 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 f122fd8..bea3fd4 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 11770aa..f892016 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 52c02b6..d6ae3ee 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -20133,7 +20133,7 @@
[(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 @@
(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 @@
(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 e733a47..9a9101e 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -670,7 +670,9 @@
(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 0000000..c27ac93
--- /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 0000000..56884f3
--- /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 0000000..30d25ad
--- /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 0000000..a0e2ff3
--- /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 0000000..98afe50
--- /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 0000000..deb0c0d
--- /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 0000000..534ddab
--- /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 0000000..333b9c8
--- /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 0000000..4af932e
--- /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 0000000..807724e
--- /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 0000000..90a0e66
--- /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 0000000..1cd3fcb
--- /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 0000000..7f02f60
--- /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 0000000..86d13b7
--- /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 0000000..4642ace
--- /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 0000000..0f44ab2
--- /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 0000000..e7a2f35
--- /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 0000000..befe0b0
--- /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 0000000..35e9de5
--- /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 0000000..ba405be
--- /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 0000000..9aebe6a
--- /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 0000000..046f107
--- /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 0000000..85819aa
--- /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 0000000..365f65f
--- /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\]*\\*%" } } */