This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/5] x86: Add -mindirect-branch-loop=


Add -mindirect-branch-loop= option to control loop filler in call and
return thunks generated by -mindirect-branch=.  'lfence' uses "lfence"
as loop filler.  'pause' uses "pause" as loop filler.  'nop' uses "nop"
as loop filler.  The default is 'lfence'.

gcc/

	* config/i386/i386-opts.h (indirect_branch_loop): New.
	* config/i386/i386.c (output_indirect_thunk): Support
	-mindirect-branch-loop=.
	* config/i386/i386.opt (mindirect-branch-loop=): New option.
	(indirect_branch_loop): New.
	(lfence): Likewise.
	(pause): Likewise.
	(nop): Likewise.
	* doc/invoke.texi: Document -mindirect-branch-loop= option.

gcc/testsuite/

	* gcc.target/i386/indirect-thunk-loop-1.c: New test.
	* gcc.target/i386/indirect-thunk-loop-2.c: Likewise.
	* gcc.target/i386/indirect-thunk-loop-3.c: Likewise.
	* gcc.target/i386/indirect-thunk-loop-4.c: Likewise.
	* gcc.target/i386/indirect-thunk-loop-5.c: Likewise.
---
 gcc/config/i386/i386-opts.h                           |  6 ++++++
 gcc/config/i386/i386.c                                | 19 +++++++++++++++++--
 gcc/config/i386/i386.opt                              | 17 +++++++++++++++++
 gcc/doc/invoke.texi                                   |  9 ++++++++-
 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c | 19 +++++++++++++++++++
 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c | 19 +++++++++++++++++++
 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c | 19 +++++++++++++++++++
 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c | 19 +++++++++++++++++++
 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c | 19 +++++++++++++++++++
 9 files changed, 143 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c

diff --git a/gcc/config/i386/i386-opts.h b/gcc/config/i386/i386-opts.h
index f14cbeee7a1..52f7cb979cc 100644
--- a/gcc/config/i386/i386-opts.h
+++ b/gcc/config/i386/i386-opts.h
@@ -114,4 +114,10 @@ enum indirect_branch {
   indirect_branch_thunk_extern
 };
 
+enum indirect_branch_loop {
+  indirect_branch_loop_lfence,
+  indirect_branch_loop_pause,
+  indirect_branch_loop_nop
+};
+
 #endif
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index ac4d1f62f50..f327a6b1b62 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -10753,8 +10753,23 @@ output_indirect_thunk (bool need_bnd_p, int regno)
 
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
 
-  /* lfence .  */
-  fprintf (asm_out_file, "\tlfence\n");
+  switch (ix86_indirect_branch_loop)
+    {
+    case indirect_branch_loop_lfence:
+      /* lfence.  */
+      fprintf (asm_out_file, "\tlfence\n");
+      break;
+    case indirect_branch_loop_pause:
+      /* pause.  */
+      fprintf (asm_out_file, "\tpause\n");
+      break;
+    case indirect_branch_loop_nop:
+      /* nop.  */
+      fprintf (asm_out_file, "\tnop\n");
+      break;
+    default:
+      gcc_unreachable ();
+    }
 
   /* Jump.  */
   fputs ("\tjmp\t", asm_out_file);
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 22c806206e4..f3e43da0aed 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -1041,3 +1041,20 @@ Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)
 
 EnumValue
 Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
+
+mindirect-branch-loop=
+Target Report RejectNegative Joined Enum(indirect_branch_loop) Var(ix86_indirect_branch_loop) Init(indirect_branch_loop_lfence)
+Control loop filler in call and return thunk for indirect call and jump.
+
+Enum
+Name(indirect_branch_loop) Type(enum indirect_branch_loop)
+Known looop choices (for use with the -mindirect-branch-loop= option):
+
+EnumValue
+Enum(indirect_branch_loop) String(lfence) Value(indirect_branch_loop_lfence)
+
+EnumValue
+Enum(indirect_branch_loop) String(pause) Value(indirect_branch_loop_pause)
+
+EnumValue
+Enum(indirect_branch_loop) String(nop) Value(indirect_branch_loop_nop)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 46461d1ada3..ee5248aba59 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1227,7 +1227,7 @@ See RS/6000 and PowerPC Options.
 -mstack-protector-guard-offset=@var{offset} @gol
 -mstack-protector-guard-symbol=@var{symbol} -mmitigate-rop @gol
 -mgeneral-regs-only -mcall-ms2sysv-xlogues @gol
--mindirect-branch=@var{choice}}
+-mindirect-branch=@var{choice} -mindirect-branch-loop=@var{choice}}
 
 @emph{x86 Windows Options}
 @gccoptlist{-mconsole  -mcygwin  -mno-cygwin  -mdll @gol
@@ -26776,6 +26776,13 @@ to external call and return thunk provided in a separate object file.
 You can control this behavior for a specific function by using the
 function attribute @code{indirect_branch}.  @xref{Function Attributes}.
 
+@item -mindirect-branch-loop=@var{choice}
+@opindex -mindirect-branch-boop
+Control loop filler in call and return thunk for indirect call and jump.
+@samp{lfence} uses @code{lfence} as loop filler.  @samp{pause} uses
+@code{pause} as loop filler.  @samp{nop} uses @code{nop} as loop filler.
+The default is @samp{lfence}.
+
 @end table
 
 These @samp{-m} switches are supported in addition to the above
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c
new file mode 100644
index 00000000000..1b0e2c58775
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=pause -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+  dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler {\tpause} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c
new file mode 100644
index 00000000000..feace47a765
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=nop -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch[256];
+
+void
+male_indirect_jump (long offset)
+{
+  dispatch[offset](offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler {\tnop} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c
new file mode 100644
index 00000000000..ad2165fa7aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=lfence -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+  dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler {\tlfence} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c
new file mode 100644
index 00000000000..4ba997da966
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk-inline -mindirect-branch-loop=pause -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+  dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler {\tpause} } } */
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c
new file mode 100644
index 00000000000..10fb2193f5e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk-extern -mindirect-branch-loop=pause -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+  dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
+/* { dg-final { scan-assembler-not {\t(lfence|pause|nop)} } } */
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
-- 
2.14.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]