Large diffs are not rendered by default.

@@ -2570,6 +2570,13 @@ struct GTY(()) machine_function {
/* Function type. */
ENUM_BITFIELD(function_type) func_type : 2;

/* How to generate indirec branch. */
ENUM_BITFIELD(indirect_branch) indirect_branch_type : 3;

/* If true, the current function has local indirect jumps, like
"indirect_jump" or "tablejump". */
BOOL_BITFIELD has_local_indirect_jump : 1;

/* If true, the current function is a function specified with
the "interrupt" or "no_caller_saved_registers" attribute. */
BOOL_BITFIELD no_caller_saved_registers : 1;
@@ -12313,13 +12313,18 @@
{
if (TARGET_X32)
operands[0] = convert_memory_address (word_mode, operands[0]);
cfun->machine->has_local_indirect_jump = true;
})

(define_insn "*indirect_jump"
[(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
""
"%!jmp\t%A0"
[(set_attr "type" "ibr")
"* return ix86_output_indirect_jmp (operands[0], false);"
[(set (attr "type")
(if_then_else (match_test "(cfun->machine->indirect_branch_type
!= indirect_branch_keep)")
(const_string "multi")
(const_string "ibr")))
(set_attr "length_immediate" "0")
(set_attr "maybe_prefix_bnd" "1")])

@@ -12362,14 +12367,19 @@

if (TARGET_X32)
operands[0] = convert_memory_address (word_mode, operands[0]);
cfun->machine->has_local_indirect_jump = true;
})

(define_insn "*tablejump_1"
[(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
(use (label_ref (match_operand 1)))]
""
"%!jmp\t%A0"
[(set_attr "type" "ibr")
"* return ix86_output_indirect_jmp (operands[0], false);"
[(set (attr "type")
(if_then_else (match_test "(cfun->machine->indirect_branch_type
!= indirect_branch_keep)")
(const_string "multi")
(const_string "ibr")))
(set_attr "length_immediate" "0")
(set_attr "maybe_prefix_bnd" "1")])

@@ -13097,8 +13107,12 @@
[(simple_return)
(use (match_operand 0 "register_operand" "r"))]
"reload_completed"
"%!jmp\t%A0"
[(set_attr "type" "ibr")
"* return ix86_output_indirect_jmp (operands[0], true);"
[(set (attr "type")
(if_then_else (match_test "(cfun->machine->indirect_branch_type
!= indirect_branch_keep)")
(const_string "multi")
(const_string "ibr")))
(set_attr "length_immediate" "0")
(set_attr "maybe_prefix_bnd" "1")])

@@ -1021,3 +1021,23 @@ indirect jump.
mforce-indirect-call
Target Report Var(flag_force_indirect_call) Init(0)
Make all function calls indirect.

mindirect-branch=
Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
Convert indirect call and jump to call and return thunks.

Enum
Name(indirect_branch) Type(enum indirect_branch)
Known indirect branch choices (for use with the -mindirect-branch= option):

EnumValue
Enum(indirect_branch) String(keep) Value(indirect_branch_keep)

EnumValue
Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk)

EnumValue
Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)

EnumValue
Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
@@ -5754,6 +5754,16 @@ Specify which floating-point unit to use. You must specify the
@code{target("fpmath=sse+387")} because the comma would separate
different options.

@item indirect_branch("@var{choice}")
@cindex @code{indirect_branch} function attribute, x86
On x86 targets, the @code{indirect_branch} attribute causes the compiler
to convert indirect call and jump with @var{choice}. @samp{keep}
keeps indirect call and jump unmodified. @samp{thunk} converts indirect
call and jump to call and return thunk. @samp{thunk-inline} converts
indirect call and jump to inlined call and return thunk.
@samp{thunk-extern} converts indirect call and jump to external call
and return thunk provided in a separate object file.

@item nocf_check
@cindex @code{nocf_check} function attribute
The @code{nocf_check} attribute on a function is used to inform the
@@ -1229,7 +1229,8 @@ See RS/6000 and PowerPC Options.
-mstack-protector-guard-reg=@var{reg} @gol
-mstack-protector-guard-offset=@var{offset} @gol
-mstack-protector-guard-symbol=@var{symbol} -mmitigate-rop @gol
-mgeneral-regs-only -mcall-ms2sysv-xlogues}
-mgeneral-regs-only -mcall-ms2sysv-xlogues @gol
-mindirect-branch=@var{choice}}

@emph{x86 Windows Options}
@gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
prevents the compiler from using floating-point, vector, mask and bound
registers.

@item -mindirect-branch=@var{choice}
@opindex -mindirect-branch
Convert indirect call and jump with @var{choice}. The default is
@samp{keep}, which keeps indirect call and jump unmodified.
@samp{thunk} converts indirect call and jump to call and return thunk.
@samp{thunk-inline} converts indirect call and jump to inlined call
and return thunk. @samp{thunk-extern} converts indirect call and jump
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}.

@end table

These @samp{-m} switches are supported in addition to the above
@@ -1,3 +1,39 @@
2018-01-14 H.J. Lu <hongjiu.lu@intel.com>

* gcc.target/i386/indirect-thunk-1.c: New test.
* gcc.target/i386/indirect-thunk-2.c: Likewise.
* gcc.target/i386/indirect-thunk-3.c: Likewise.
* gcc.target/i386/indirect-thunk-4.c: Likewise.
* gcc.target/i386/indirect-thunk-5.c: Likewise.
* gcc.target/i386/indirect-thunk-6.c: Likewise.
* gcc.target/i386/indirect-thunk-7.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
* gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
* gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
* gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
* gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-7.c: Likewise.

2018-01-14 Jan Hubicka <hubicka@ucw.cz>

PR ipa/83051
@@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk -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} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk -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 {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,21 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch;

int
male_indirect_jump (long offset)
{
dispatch(offset);
return 0;
}

/* { 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 "call\[ \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} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,21 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch[256];

int
male_indirect_jump (long offset)
{
dispatch[offset](offset);
return 0;
}

/* { 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 "call\[ \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} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,17 @@
/* { dg-do compile { target *-*-linux* } } */
/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */

extern void bar (void);

void
foo (void)
{
bar ();
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,18 @@
/* { dg-do compile { target *-*-linux* } } */
/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */

extern void bar (void);

int
foo (void)
{
bar ();
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,44 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */

void func0 (void);
void func1 (void);
void func2 (void);
void func3 (void);
void func4 (void);
void func4 (void);
void func5 (void);

void
bar (int i)
{
switch (i)
{
default:
func0 ();
break;
case 1:
func1 ();
break;
case 2:
func2 ();
break;
case 3:
func3 ();
break;
case 4:
func4 ();
break;
case 5:
func5 ();
break;
}
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { 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} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,23 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch;

extern void male_indirect_jump (long)
__attribute__ ((indirect_branch("thunk")));

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} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,21 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch[256];

__attribute__ ((indirect_branch("thunk")))
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 {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,23 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch;
extern int male_indirect_jump (long)
__attribute__ ((indirect_branch("thunk-inline")));

int
male_indirect_jump (long offset)
{
dispatch(offset);
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
@@ -0,0 +1,22 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch[256];

__attribute__ ((indirect_branch("thunk-inline")))
int
male_indirect_jump (long offset)
{
dispatch[offset](offset);
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
@@ -0,0 +1,22 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch;
extern int male_indirect_jump (long)
__attribute__ ((indirect_branch("thunk-extern")));

int
male_indirect_jump (long offset)
{
dispatch(offset);
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
@@ -0,0 +1,21 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch[256];

__attribute__ ((indirect_branch("thunk-extern")))
int
male_indirect_jump (long offset)
{
dispatch[offset](offset);
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
@@ -0,0 +1,44 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-pic" } */

void func0 (void);
void func1 (void);
void func2 (void);
void func3 (void);
void func4 (void);
void func4 (void);
void func5 (void);

__attribute__ ((indirect_branch("thunk-extern")))
void
bar (int i)
{
switch (i)
{
default:
func0 ();
break;
case 1:
func1 ();
break;
case 2:
func2 ();
break;
case 3:
func3 ();
break;
case 4:
func4 ();
break;
case 5:
func5 ();
break;
}
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
@@ -0,0 +1,42 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */

void func0 (void);
void func1 (void);
void func2 (void);
void func3 (void);
void func4 (void);
void func4 (void);
void func5 (void);

__attribute__ ((indirect_branch("keep")))
void
bar (int i)
{
switch (i)
{
default:
func0 ();
break;
case 1:
func1 ();
break;
case 2:
func2 ();
break;
case 3:
func3 ();
break;
case 4:
func4 ();
break;
case 5:
func5 ();
break;
}
}

/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
@@ -0,0 +1,20 @@
/* { dg-do compile { target { ! x32 } } } */
/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */

void (*dispatch) (char *);
char buf[10];

void
foo (void)
{
dispatch (buf);
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler "bnd ret" } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,21 @@
/* { dg-do compile { target { ! x32 } } } */
/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */

void (*dispatch) (char *);
char buf[10];

int
foo (void)
{
dispatch (buf);
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler "bnd ret" } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,19 @@
/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */

void bar (char *);
char buf[10];

void
foo (void)
{
bar (buf);
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler "bnd ret" } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,20 @@
/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */

void bar (char *);
char buf[10];

int
foo (void)
{
bar (buf);
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler-times "bnd call\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler "bnd ret" } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
@@ -0,0 +1,19 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-extern -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)} } } */
/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
@@ -0,0 +1,19 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-extern -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-not {\t(lfence|pause)} } } */
/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
@@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch;

int
male_indirect_jump (long offset)
{
dispatch(offset);
return 0;
}

/* { 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-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
@@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch[256];

int
male_indirect_jump (long offset)
{
dispatch[offset](offset);
return 0;
}

/* { 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-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
@@ -0,0 +1,16 @@
/* { dg-do compile { target *-*-linux* } } */
/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */

extern void bar (void);

void
foo (void)
{
bar ();
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
@@ -0,0 +1,17 @@
/* { dg-do compile { target *-*-linux* } } */
/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */

extern void bar (void);

int
foo (void)
{
bar ();
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
@@ -0,0 +1,43 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */

void func0 (void);
void func1 (void);
void func2 (void);
void func3 (void);
void func4 (void);
void func4 (void);
void func5 (void);

void
bar (int i)
{
switch (i)
{
default:
func0 ();
break;
case 1:
func1 ();
break;
case 2:
func2 ();
break;
case 3:
func3 ();
break;
case 4:
func4 ();
break;
case 5:
func5 ();
break;
}
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { 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)} } } */
/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
@@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-inline -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 {\tlfence} } } */
/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
@@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-inline -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\]*\.LIND" } } */
/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
@@ -0,0 +1,21 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch;

int
male_indirect_jump (long offset)
{
dispatch(offset);
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler-times {\tpause} 1 } } */
/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
@@ -0,0 +1,21 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */

typedef void (*dispatch_t)(long offset);

dispatch_t dispatch[256];

int
male_indirect_jump (long offset)
{
dispatch[offset](offset);
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler-times {\tpause} 1 } } */
/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
@@ -0,0 +1,17 @@
/* { dg-do compile { target *-*-linux* } } */
/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */

extern void bar (void);

void
foo (void)
{
bar ();
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
/* { dg-final { scan-assembler {\tpause} } } */
/* { dg-final { scan-assembler {\tlfence} } } */
/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
@@ -0,0 +1,18 @@
/* { dg-do compile { target *-*-linux* } } */
/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */

extern void bar (void);

int
foo (void)
{
bar ();
return 0;
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
/* { dg-final { scan-assembler-times {\tpause} 1 } } */
/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
@@ -0,0 +1,44 @@
/* { dg-do compile } */
/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */

void func0 (void);
void func1 (void);
void func2 (void);
void func3 (void);
void func4 (void);
void func4 (void);
void func5 (void);

void
bar (int i)
{
switch (i)
{
default:
func0 ();
break;
case 1:
func1 ();
break;
case 2:
func2 ();
break;
case 3:
func3 ();
break;
case 4:
func4 ();
break;
case 5:
func5 ();
break;
}
}

/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { 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 {\tlfence} } } */
/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */