@@ -274,6 +274,8 @@ extern void x86_output_aligned_bss (FILE *, tree, const char *,
extern void x86_elf_aligned_common (FILE *, const char *,
unsigned HOST_WIDE_INT, int);
+extern bool ix86_output_rex_prefix_p (rtx, rtx);
+
#ifdef RTX_CODE
extern void ix86_fp_comparison_codes (enum rtx_code code, enum rtx_code *,
enum rtx_code *, enum rtx_code *);
@@ -14510,6 +14510,29 @@ i386_asm_output_addr_const_extra (FILE *file, rtx x)
return true;
}
+
+/* Since x64-64 linker IE->LE transition requires a REX prefix, we
+ output a REX prefix if there isn't one. */
+
+bool
+ix86_output_rex_prefix_p (rtx dest, rtx op)
+{
+ if (!TARGET_X32
+ || GET_MODE (dest) != SImode
+ || REX_INT_REG_P (dest)
+ || !MEM_P (op))
+ return false;
+
+ op = XEXP (op, 0);
+ if (GET_CODE (op) != CONST)
+ return false;
+
+ op = XEXP (op, 0);
+ if (GET_CODE (op) != UNSPEC)
+ return false;
+
+ return XINT (op, 1) == UNSPEC_GOTNTPOFF;
+}
/* Split one or more double-mode RTL references into pairs of half-mode
references. The RTL can be REG, offsettable MEM, integer constant, or
@@ -2287,7 +2287,11 @@
default:
gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1]));
- return "mov{l}\t{%1, %0|%0, %1}";
+ /* Output REX prefix if needed. */
+ if (ix86_output_rex_prefix_p (operands[0], operands[1]))
+ return "rex mov{l}\t{%1, %0|%0, %1}";
+ else
+ return "mov{l}\t{%1, %0|%0, %1}";
}
}
[(set (attr "type")
@@ -5616,7 +5620,11 @@
if (x86_maybe_negate_const_int (&operands[2], <MODE>mode))
return "sub{<imodesuffix>}\t{%2, %0|%0, %2}";
- return "add{<imodesuffix>}\t{%2, %0|%0, %2}";
+ /* Output REX prefix if needed. */
+ if (ix86_output_rex_prefix_p (operands[0], operands[2]))
+ return "rex add{<imodesuffix>}\t{%2, %0|%0, %2}";
+ else
+ return "add{<imodesuffix>}\t{%2, %0|%0, %2}";
}
}
[(set (attr "type")