aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config
diff options
context:
space:
mode:
authorCaroline Tice <cmtice@google.com>2018-01-29 13:36:52 -0800
committerCaroline Tice <cmtice@google.com>2018-01-29 22:19:21 +0000
commitd64d815b3af9d2653d924ea2e1ebb21ee8b043b7 (patch)
tree41ddc808254fa6b40de6540413015909760ec306 /gcc-4.9/gcc/config
parent430f43829fa42b459ccbb53b44843c54c8ba4550 (diff)
downloadtoolchain_gcc-d64d815b3af9d2653d924ea2e1ebb21ee8b043b7.tar.gz
toolchain_gcc-d64d815b3af9d2653d924ea2e1ebb21ee8b043b7.tar.bz2
toolchain_gcc-d64d815b3af9d2653d924ea2e1ebb21ee8b043b7.zip
[GCC] Update with latest retpoline fixes from Intel.
Intel has updated their retpoline patches since we created our original patch. This CL updates our retpoline changes to match the latest from Intel. Bug: None Test: Tested extensively in ChromeOS. Built x86 platform & kernel images in Android. Change-Id: Id1a18cb1f1f4461832a017cb5c5d59e5400d9d08
Diffstat (limited to 'gcc-4.9/gcc/config')
-rw-r--r--gcc-4.9/gcc/config/i386/constraints.md3
-rw-r--r--gcc-4.9/gcc/config/i386/i386-opts.h11
-rw-r--r--gcc-4.9/gcc/config/i386/i386.c269
-rw-r--r--gcc-4.9/gcc/config/i386/i386.md22
-rw-r--r--gcc-4.9/gcc/config/i386/i386.opt22
-rw-r--r--gcc-4.9/gcc/config/i386/predicates.md6
6 files changed, 245 insertions, 88 deletions
diff --git a/gcc-4.9/gcc/config/i386/constraints.md b/gcc-4.9/gcc/config/i386/constraints.md
index 567e70564..ce1481122 100644
--- a/gcc-4.9/gcc/config/i386/constraints.md
+++ b/gcc-4.9/gcc/config/i386/constraints.md
@@ -153,7 +153,8 @@
(define_constraint "w"
"@internal Call memory operand."
- (and (not (match_test "TARGET_X32"))
+ (and (not (match_test "ix86_indirect_branch_register"))
+ (not (match_test "TARGET_X32"))
(match_operand 0 "memory_operand")))
;; Integer constant constraints.
diff --git a/gcc-4.9/gcc/config/i386/i386-opts.h b/gcc-4.9/gcc/config/i386/i386-opts.h
index e98cd8c1e..f44620781 100644
--- a/gcc-4.9/gcc/config/i386/i386-opts.h
+++ b/gcc-4.9/gcc/config/i386/i386-opts.h
@@ -93,6 +93,11 @@ enum stack_protector_guard {
SSP_GLOBAL /* global canary */
};
+/* This is used to mitigate variant #2 of the speculative execution
+ vulnerabilities on x86 processors identified by CVE-2017-5715, aka
+ Spectre. They convert indirect branches and function returns to
+ call and return thunks to avoid speculative execution via indirect
+ call, jmp and ret. */
enum indirect_branch {
indirect_branch_unset = 0,
indirect_branch_keep,
@@ -101,10 +106,4 @@ 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-4.9/gcc/config/i386/i386.c b/gcc-4.9/gcc/config/i386/i386.c
index ccd2f150b..975a84dea 100644
--- a/gcc-4.9/gcc/config/i386/i386.c
+++ b/gcc-4.9/gcc/config/i386/i386.c
@@ -2515,7 +2515,11 @@ make_pass_insert_vzeroupper (gcc::context *ctxt)
there are local indirect jumps, like "indirect_jump" or "tablejump",
which jumps to another place in the function, since "call" in the
indirect thunk pushes the return address onto stack, destroying
- red-zone. */
+ red-zone.
+
+ TODO: If we can reserve the first 2 WORDs, for PUSH and, another
+ for CALL, in red-zone, we can allow local indirect jumps with
+ indirect thunk. */
static inline bool
ix86_using_red_zone (void)
@@ -4954,6 +4958,19 @@ ix86_set_indirect_branch_type (tree fndecl)
}
else
cfun->machine->indirect_branch_type = ix86_indirect_branch;
+
+ /* -mcmodel=large is not compatible with -mindirect-branch=thunk
+ nor -mindirect-branch=thunk-extern. */
+ if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
+ && ((cfun->machine->indirect_branch_type
+ == indirect_branch_thunk_extern)
+ || (cfun->machine->indirect_branch_type
+ == indirect_branch_thunk)))
+ error ("%<-mindirect-branch=%s%> and %<-mcmodel=large%> are not "
+ "compatible",
+ ((cfun->machine->indirect_branch_type
+ == indirect_branch_thunk_extern)
+ ? "thunk-extern" : "thunk"));
}
if (cfun->machine->function_return_type == indirect_branch_unset)
@@ -4979,6 +4996,19 @@ ix86_set_indirect_branch_type (tree fndecl)
}
else
cfun->machine->function_return_type = ix86_function_return;
+
+ /* -mcmodel=large is not compatible with -mfunction-return=thunk
+ nor -mfunction-return=thunk-extern. */
+ if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
+ && ((cfun->machine->function_return_type
+ == indirect_branch_thunk_extern)
+ || (cfun->machine->function_return_type
+ == indirect_branch_thunk)))
+ error ("%<-mfunction-return=%s%> and %<-mcmodel=large%> are not "
+ "compatible",
+ ((cfun->machine->function_return_type
+ == indirect_branch_thunk_extern)
+ ? "thunk-extern" : "thunk"));
}
}
@@ -9168,9 +9198,15 @@ ix86_setup_frame_addresses (void)
# endif
#endif
+/* Label count for call and return thunks. It is used to make unique
+ labels in call and return thunks. */
static int indirectlabelno;
+
+/* True if call and return thunk functions are needed. */
static bool indirect_thunk_needed = false;
+/* Bit masks of integer registers, which contain branch target, used
+ by call and return thunks functions. */
static int indirect_thunks_used;
#ifndef INDIRECT_LABEL
@@ -9194,13 +9230,13 @@ indirect_thunk_name (char name[32], int regno, bool ret_p)
reg_prefix = TARGET_64BIT ? "r" : "e";
else
reg_prefix = "";
- sprintf (name, "__x86.indirect_thunk.%s%s",
+ sprintf (name, "__x86_indirect_thunk_%s%s",
reg_prefix, reg_names[regno]);
}
else
{
const char *ret = ret_p ? "return" : "indirect";
- sprintf (name, "__x86.%s_thunk", ret);
+ sprintf (name, "__x86_%s_thunk", ret);
}
}
else
@@ -9217,6 +9253,30 @@ indirect_thunk_name (char name[32], int regno, bool ret_p)
}
}
+/* Output a call and return thunk for indirect branch. If REGNO != -1,
+ the function address is in REGNO and the call and return thunk looks
+ like:
+
+ call L2
+ L1:
+ pause
+ jmp L1
+ L2:
+ mov %REG, (%sp)
+ ret
+
+ Otherwise, the function address is on the top of stack and the
+ call and return thunk looks like:
+
+ call L2
+ L1:
+ pause
+ jmp L1
+ L2:
+ lea WORD_SIZE(%sp), %sp
+ ret
+ */
+
static void
output_indirect_thunk (int regno)
{
@@ -9235,23 +9295,8 @@ output_indirect_thunk (int regno)
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
- 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 ();
- }
+ /* Pause + lfence. */
+ fprintf (asm_out_file, "\tpause\n\tlfence\n");
/* Jump. */
fputs ("\tjmp\t", asm_out_file);
@@ -9280,13 +9325,17 @@ output_indirect_thunk (int regno)
fputs ("\tret\n", asm_out_file);
}
+/* Output a funtion with a call and return thunk for indirect branch.
+ If REGNO != -1, the function address is in REGNO. Otherwise, the
+ function address is on the top of stack. */
+
static void
output_indirect_thunk_function (int regno)
{
char name[32];
tree decl;
- /* Create __x86.indirect_thunk. */
+ /* Create __x86_indirect_thunk. */
indirect_thunk_name (name, regno, false);
decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
get_identifier (name),
@@ -9332,11 +9381,10 @@ output_indirect_thunk_function (int regno)
if (regno < 0)
{
- /* Create alias for __x86.return_thunk. */
+ /* Create alias for __x86_return_thunk. */
char alias[32];
indirect_thunk_name (alias, regno, true);
- ASM_OUTPUT_DEF (asm_out_file, alias, name);
#if TARGET_MACHO
if (TARGET_MACHO)
{
@@ -9345,8 +9393,10 @@ output_indirect_thunk_function (int regno)
fputs ("\n\t.private_extern\t", asm_out_file);
assemble_name (asm_out_file, alias);
putc ('\n', asm_out_file);
+ ASM_OUTPUT_LABEL (asm_out_file, alias);
}
#else
+ ASM_OUTPUT_DEF (asm_out_file, alias, name);
if (USE_HIDDEN_LINKONCE)
{
fputs ("\t.globl\t", asm_out_file);
@@ -10981,6 +11031,7 @@ ix86_expand_prologue (void)
{
struct machine_function *m = cfun->machine;
rtx insn, t;
+ struct ix86_frame frame;
bool pic_reg_used;
HOST_WIDE_INT allocate;
bool int_registers_saved;
@@ -11004,7 +11055,7 @@ ix86_expand_prologue (void)
m->fs.sp_valid = true;
ix86_compute_frame_layout ();
- struct ix86_frame &frame = m->frame;
+ frame = m->frame;
if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
{
@@ -11737,12 +11788,13 @@ ix86_expand_epilogue (int style)
{
struct machine_function *m = cfun->machine;
struct machine_frame_state frame_state_save = m->fs;
+ struct ix86_frame frame;
bool restore_regs_via_mov;
bool using_drap;
ix86_finalize_stack_realign_flags ();
ix86_compute_frame_layout ();
- struct ix86_frame &frame = m->frame;
+ frame = m->frame;
m->fs.sp_valid = (!frame_pointer_needed
|| (crtl->sp_is_unchanging
@@ -14931,7 +14983,7 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, bool reverse,
If CODE is 'h', pretend the reg is the 'high' byte register.
If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
If CODE is 'd', duplicate the operand for AVX instruction.
- If CODE is 'V', print naked register name without %.
+ If CODE is 'V', print naked full integer register name without %.
*/
void
@@ -14976,6 +15028,13 @@ print_reg (rtx x, int code, FILE *file)
code = 32;
else if (code == 'g')
code = 64;
+ else if (code == 'V')
+ {
+ if (GENERAL_REGNO_P (regno))
+ code = GET_MODE_SIZE (word_mode);
+ else
+ error ("'V' modifier on non-integer register");
+ }
else
code = GET_MODE_SIZE (GET_MODE (x));
@@ -15142,7 +15201,7 @@ get_some_local_dynamic_name (void)
& -- print some in-use local-dynamic symbol name.
H -- print a memory address offset by 8; used for sse high-parts
Y -- print condition for XOP pcom* instruction.
- V -- print naked register name without %.
+ V -- print naked full integer register name without %.
+ -- print a branch hint as 'cs' or 'ds' prefix
; -- print a semicolon (after prefixes due to bug in older gas).
~ -- print "i" if TARGET_AVX2, "f" otherwise.
@@ -25304,48 +25363,131 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
return call;
}
+/* Output indirect branch via a call and return thunk. CALL_OP is a
+ register which contains the branch target. XASM is the assembly
+ template for CALL_OP. Branch is a tail call if SIBCALL_P is true.
+ A normal call is converted to:
+
+ call __x86_indirect_thunk_reg
+
+ and a tail call is converted to:
+
+ jmp __x86_indirect_thunk_reg
+ */
+
static void
-ix86_output_indirect_branch (rtx call_op, const char *xasm,
- bool sibcall_p)
+ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
{
char thunk_name_buf[32];
char *thunk_name;
- char push_buf[64];
- int regno;
-
- if (REG_P (call_op))
- regno = REGNO (call_op);
- else
- regno = -1;
+ int regno = REGNO (call_op);
if (cfun->machine->indirect_branch_type
!= indirect_branch_thunk_inline)
{
if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
- {
- if (regno >= 0)
- {
- int i = regno;
- if (i >= FIRST_REX_INT_REG)
- i -= (FIRST_REX_INT_REG - SP_REG - 1);
- indirect_thunks_used |= 1 << i;
- }
- else
- indirect_thunk_needed = true;
- }
+ {
+ int i = regno;
+ if (i >= FIRST_REX_INT_REG)
+ i -= (FIRST_REX_INT_REG - SP_REG - 1);
+ indirect_thunks_used |= 1 << i;
+ }
indirect_thunk_name (thunk_name_buf, regno, false);
thunk_name = thunk_name_buf;
}
else
thunk_name = NULL;
+ if (sibcall_p)
+ {
+ if (thunk_name != NULL)
+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
+ else
+ output_indirect_thunk (regno);
+ }
+ else
+ {
+ if (thunk_name != NULL)
+ {
+ fprintf (asm_out_file, "\tcall\t%s\n", thunk_name);
+ return;
+ }
+
+ char indirectlabel1[32];
+ char indirectlabel2[32];
+
+ ASM_GENERATE_INTERNAL_LABEL (indirectlabel1,
+ INDIRECT_LABEL,
+ indirectlabelno++);
+ ASM_GENERATE_INTERNAL_LABEL (indirectlabel2,
+ INDIRECT_LABEL,
+ indirectlabelno++);
+
+ /* Jump. */
+ fputs ("\tjmp\t", asm_out_file);
+ assemble_name_raw (asm_out_file, indirectlabel2);
+ fputc ('\n', asm_out_file);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
+
+ if (thunk_name != NULL)
+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
+ else
+ output_indirect_thunk (regno);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
+
+ /* Call. */
+ fputs ("\tcall\t", asm_out_file);
+ assemble_name_raw (asm_out_file, indirectlabel1);
+ fputc ('\n', asm_out_file);
+ }
+}
+
+/* Output indirect branch via a call and return thunk. CALL_OP is
+ the branch target. XASM is the assembly template for CALL_OP.
+ Branch is a tail call if SIBCALL_P is true. A normal call is
+ converted to:
+
+ jmp L2
+ L1:
+ push CALL_OP
+ jmp __x86_indirect_thunk
+ L2:
+ call L1
+
+ and a tail call is converted to:
+
+ push CALL_OP
+ jmp __x86_indirect_thunk
+ */
+
+static void
+ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
+ bool sibcall_p)
+{
+ char thunk_name_buf[32];
+ char *thunk_name;
+ char push_buf[64];
+ int regno = -1;
+
+ if (cfun->machine->indirect_branch_type
+ != indirect_branch_thunk_inline)
+ {
+ if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
+ indirect_thunk_needed = true;
+ indirect_thunk_name (thunk_name_buf, regno, false);
+ thunk_name = thunk_name_buf;
+ }
+ else
+ thunk_name = NULL;
+
snprintf (push_buf, sizeof (push_buf), "push{%c}\t%s",
TARGET_64BIT ? 'q' : 'l', xasm);
if (sibcall_p)
{
- if (regno < 0)
- output_asm_insn (push_buf, &call_op);
+ output_asm_insn (push_buf, &call_op);
if (thunk_name != NULL)
fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
else
@@ -25353,12 +25495,6 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm,
}
else
{
- if (regno >= 0 && thunk_name != NULL)
- {
- fprintf (asm_out_file, "\tcall\t%s\n", thunk_name);
- return;
- }
-
char indirectlabel1[32];
char indirectlabel2[32];
@@ -25376,6 +25512,7 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm,
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
+ /* An external function may be called via GOT, instead of PLT. */
if (MEM_P (call_op))
{
struct ix86_address parts;
@@ -25408,8 +25545,7 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm,
}
}
- if (regno < 0)
- output_asm_insn (push_buf, &call_op);
+ output_asm_insn (push_buf, &call_op);
if (thunk_name != NULL)
fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
@@ -25425,6 +25561,22 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm,
}
}
+/* Output indirect branch via a call and return thunk. CALL_OP is
+ the branch target. XASM is the assembly template for CALL_OP.
+ Branch is a tail call if SIBCALL_P is true. */
+
+static void
+ix86_output_indirect_branch (rtx call_op, const char *xasm,
+ bool sibcall_p)
+{
+ if (REG_P (call_op))
+ ix86_output_indirect_branch_via_reg (call_op, sibcall_p);
+ else
+ ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p);
+}
+/* Output indirect jump. CALL_OP is the jump target. Jump is a
+ function return if RET_P is true. */
+
const char *
ix86_output_indirect_jmp (rtx call_op, bool ret_p)
{
@@ -25468,6 +25620,9 @@ ix86_nopic_noplt_attribute_p (rtx call_op)
return false;
}
+/* Output function return. CALL_OP is the jump target. Add a REP
+ prefix to RET if LONG_P is true and function return is kept. */
+
const char *
ix86_output_function_return (bool long_p)
{
diff --git a/gcc-4.9/gcc/config/i386/i386.md b/gcc-4.9/gcc/config/i386/i386.md
index e32ba52a6..f5eff3d90 100644
--- a/gcc-4.9/gcc/config/i386/i386.md
+++ b/gcc-4.9/gcc/config/i386/i386.md
@@ -11140,7 +11140,7 @@
[(set (pc) (match_operand 0 "indirect_branch_operand"))]
""
{
- if (TARGET_X32)
+ if (TARGET_X32 || ix86_indirect_branch_register)
operands[0] = convert_memory_address (word_mode, operands[0]);
cfun->machine->has_local_indirect_jump = true;
})
@@ -11149,7 +11149,11 @@
[(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))]
""
"* return ix86_output_indirect_jmp (operands[0], false);"
- [(set_attr "type" "ibr")
+ [(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")])
(define_expand "tablejump"
@@ -11189,7 +11193,7 @@
OPTAB_DIRECT);
}
- if (TARGET_X32)
+ if (TARGET_X32 || ix86_indirect_branch_register)
operands[0] = convert_memory_address (word_mode, operands[0]);
cfun->machine->has_local_indirect_jump = true;
})
@@ -11199,7 +11203,11 @@
(use (label_ref (match_operand 1)))]
""
"* return ix86_output_indirect_jmp (operands[0], false);"
- [(set_attr "type" "ibr")
+ [(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")])
;; Convert setcc + movzbl to xor + setcc if operands don't overlap.
@@ -11620,7 +11628,11 @@
(use (match_operand:SI 0 "register_operand" "r"))]
"reload_completed"
"* return ix86_output_indirect_jmp (operands[0], true);"
- [(set_attr "type" "ibr")
+ [(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")])
(define_insn "nop"
diff --git a/gcc-4.9/gcc/config/i386/i386.opt b/gcc-4.9/gcc/config/i386/i386.opt
index 3b4a86066..502037b68 100644
--- a/gcc-4.9/gcc/config/i386/i386.opt
+++ b/gcc-4.9/gcc/config/i386/i386.opt
@@ -797,11 +797,11 @@ Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
mindirect-branch=
Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
-Update indirect call and jump.
+Convert indirect call and jump to call and return thunks.
mfunction-return=
Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_function_return) Init(indirect_branch_keep)
-Update function return.
+Convert function return to call and return thunk.
Enum
Name(indirect_branch) Type(enum indirect_branch)
@@ -819,18 +819,6 @@ 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) Undocumented Init(indirect_branch_loop_lfence)
-
-Enum
-Name(indirect_branch_loop) Type(enum indirect_branch_loop)
-Known loop 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)
+mindirect-branch-register
+Target Report Var(ix86_indirect_branch_register) Init(0)
+Force indirect call and jump via register.
diff --git a/gcc-4.9/gcc/config/i386/predicates.md b/gcc-4.9/gcc/config/i386/predicates.md
index 8266f3eaf..10afa385c 100644
--- a/gcc-4.9/gcc/config/i386/predicates.md
+++ b/gcc-4.9/gcc/config/i386/predicates.md
@@ -584,7 +584,8 @@
;; Test for a valid operand for indirect branch.
(define_predicate "indirect_branch_operand"
(ior (match_operand 0 "register_operand")
- (and (not (match_test "TARGET_X32"))
+ (and (not (match_test "ix86_indirect_branch_register"))
+ (not (match_test "TARGET_X32"))
(match_operand 0 "memory_operand"))))
;; Test for a valid operand for a call instruction.
@@ -593,7 +594,8 @@
(ior (match_test "constant_call_address_operand
(op, mode == VOIDmode ? mode : Pmode)")
(match_operand 0 "call_register_no_elim_operand")
- (and (not (match_test "TARGET_X32"))
+ (and (not (match_test "ix86_indirect_branch_register"))
+ (not (match_test "TARGET_X32"))
(match_operand 0 "memory_operand"))))
;; Similarly, but for tail calls, in which we cannot allow memory references.