@@ -586,6 +586,9 @@ ix86_target_macros (void)
ix86_tune,
ix86_fpmath,
cpp_define);
+
+ cpp_define (parse_in, "__SEG_FS");
+ cpp_define (parse_in, "__SEG_GS");
}
@@ -600,6 +603,9 @@ ix86_register_pragmas (void)
/* Update pragma hook to allow parsing #pragma GCC target. */
targetm.target_option.pragma_parse = ix86_pragma_target_parse;
+ c_register_addr_space ("__seg_fs", ADDR_SPACE_SEG_FS);
+ c_register_addr_space ("__seg_gs", ADDR_SPACE_SEG_GS);
+
#ifdef REGISTER_SUBTARGET_PRAGMAS
REGISTER_SUBTARGET_PRAGMAS ();
#endif
@@ -326,3 +326,6 @@ struct ix86_first_cycle_multipass_data_
# define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T \
struct ix86_first_cycle_multipass_data_
#endif /* RTX_CODE */
+
+const addr_space_t ADDR_SPACE_SEG_FS = 1;
+const addr_space_t ADDR_SPACE_SEG_GS = 2;
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. If not see
static rtx legitimize_dllimport_symbol (rtx, bool);
static rtx legitimize_pe_coff_extern_decl (rtx, bool);
static rtx legitimize_pe_coff_symbol (rtx, bool);
+static void ix86_print_operand_address_as (FILE *file, rtx addr, addr_space_t);
#ifndef CHECK_STACK_LIMIT
#define CHECK_STACK_LIMIT (-1)
@@ -17123,32 +17124,22 @@ ix86_print_operand (FILE *file, rtx x, int code)
else if (MEM_P (x))
{
- /* No `byte ptr' prefix for call instructions or BLKmode operands. */
- if (ASSEMBLER_DIALECT == ASM_INTEL && code != 'X' && code != 'P'
- && GET_MODE (x) != BLKmode)
+ rtx addr = XEXP (x, 0);
+
+ /* Avoid (%rip) for call operands. */
+ if (code == 'P' && CONSTANT_ADDRESS_P (x) && !CONST_INT_P (x))
{
- const char * size;
- switch (GET_MODE_SIZE (GET_MODE (x)))
- {
- case 1: size = "BYTE"; break;
- case 2: size = "WORD"; break;
- case 4: size = "DWORD"; break;
- case 8: size = "QWORD"; break;
- case 12: size = "TBYTE"; break;
- case 16:
- if (GET_MODE (x) == XFmode)
- size = "TBYTE";
- else
- size = "XMMWORD";
- break;
- case 32: size = "YMMWORD"; break;
- case 64: size = "ZMMWORD"; break;
- default:
- gcc_unreachable ();
- }
+ output_addr_const (file, addr);
+ return;
+ }
+
+ /* No `byte ptr' prefix for call instructions ... */
+ if (ASSEMBLER_DIALECT == ASM_INTEL && code != 'X' && code != 'P')
+ {
+ machine_mode mode = GET_MODE (x);
+ const char *size;
- /* Check for explicit size override (codes 'b', 'w', 'k',
- 'q' and 'x') */
+ /* Check for explicit size override codes. */
if (code == 'b')
size = "BYTE";
else if (code == 'w')
@@ -17159,20 +17150,39 @@ ix86_print_operand (FILE *file, rtx x, int code)
size = "QWORD";
else if (code == 'x')
size = "XMMWORD";
-
- fputs (size, file);
- fputs (" PTR ", file);
+ else if (mode == BLKmode)
+ /* ... or BLKmode operands, when not overridden. */
+ size = NULL;
+ else
+ switch (GET_MODE_SIZE (mode))
+ {
+ case 1: size = "BYTE"; break;
+ case 2: size = "WORD"; break;
+ case 4: size = "DWORD"; break;
+ case 8: size = "QWORD"; break;
+ case 12: size = "TBYTE"; break;
+ case 16:
+ if (mode == XFmode)
+ size = "TBYTE";
+ else
+ size = "XMMWORD";
+ break;
+ case 32: size = "YMMWORD"; break;
+ case 64: size = "ZMMWORD"; break;
+ default:
+ gcc_unreachable ();
+ }
+ if (size)
+ {
+ fputs (size, file);
+ fputs (" PTR ", file);
+ }
}
- x = XEXP (x, 0);
- /* Avoid (%rip) for call operands. */
- if (CONSTANT_ADDRESS_P (x) && code == 'P'
- && !CONST_INT_P (x))
- output_addr_const (file, x);
- else if (this_is_asm_operands && ! address_operand (x, VOIDmode))
+ if (this_is_asm_operands && ! address_operand (addr, VOIDmode))
output_operand_lossage ("invalid constraints for operand");
else
- output_address (x);
+ ix86_print_operand_address_as (file, addr, MEM_ADDR_SPACE (x));
}
else if (CONST_DOUBLE_P (x) && GET_MODE (x) == SFmode)
@@ -17257,7 +17267,7 @@ ix86_print_operand_punct_valid_p (unsigned char code)
/* Print a memory operand whose address is ADDR. */
static void
-ix86_print_operand_address (FILE *file, rtx addr)
+ix86_print_operand_address_as (FILE *file, rtx addr, addr_space_t as)
{
struct ix86_address parts;
rtx base, index, disp;
@@ -17310,18 +17320,22 @@ ix86_print_operand_address (FILE *file, rtx addr)
disp = parts.disp;
scale = parts.scale;
- switch (parts.seg)
+ if (ADDR_SPACE_GENERIC_P (as))
+ as = parts.seg;
+ else
+ gcc_assert (ADDR_SPACE_GENERIC_P (parts.seg));
+
+ if (!ADDR_SPACE_GENERIC_P (as))
{
- case SEG_DEFAULT:
- break;
- case SEG_FS:
- case SEG_GS:
- if (ASSEMBLER_DIALECT == ASM_ATT)
- putc ('%', file);
- fputs ((parts.seg == SEG_FS ? "fs:" : "gs:"), file);
- break;
- default:
- gcc_unreachable ();
+ const char *string;
+
+ if (as == ADDR_SPACE_SEG_FS)
+ string = (ASSEMBLER_DIALECT == ASM_ATT ? "%fs:" : "fs:");
+ else if (as == ADDR_SPACE_SEG_GS)
+ string = (ASSEMBLER_DIALECT == ASM_ATT ? "%gs:" : "gs:");
+ else
+ gcc_unreachable ();
+ fputs (string, file);
}
/* Use one byte shorter RIP relative addressing for 64bit mode. */
@@ -17480,6 +17494,12 @@ ix86_print_operand_address (FILE *file, rtx addr)
}
}
+static void
+ix86_print_operand_address (FILE *file, rtx addr)
+{
+ ix86_print_operand_address_as (file, addr, ADDR_SPACE_GENERIC);
+}
+
/* Implementation of TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA. */
static bool
@@ -27253,25 +27273,35 @@ ix86_attr_length_address_default (rtx_insn *insn)
extract_insn_cached (insn);
for (i = recog_data.n_operands - 1; i >= 0; --i)
- if (MEM_P (recog_data.operand[i]))
- {
- constrain_operands_cached (insn, reload_completed);
- if (which_alternative != -1)
- {
- const char *constraints = recog_data.constraints[i];
- int alt = which_alternative;
-
- while (*constraints == '=' || *constraints == '+')
- constraints++;
- while (alt-- > 0)
- while (*constraints++ != ',')
- ;
- /* Skip ignored operands. */
- if (*constraints == 'X')
- continue;
- }
- return memory_address_length (XEXP (recog_data.operand[i], 0), false);
- }
+ {
+ rtx op = recog_data.operand[i];
+ if (MEM_P (op))
+ {
+ constrain_operands_cached (insn, reload_completed);
+ if (which_alternative != -1)
+ {
+ const char *constraints = recog_data.constraints[i];
+ int alt = which_alternative;
+
+ while (*constraints == '=' || *constraints == '+')
+ constraints++;
+ while (alt-- > 0)
+ while (*constraints++ != ',')
+ ;
+ /* Skip ignored operands. */
+ if (*constraints == 'X')
+ continue;
+ }
+
+ int len = memory_address_length (XEXP (op, 0), false);
+
+ /* Account for segment prefix for non-default addr spaces. */
+ if (!ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (op)))
+ len++;
+
+ return len;
+ }
+ }
return 0;
}
@@ -53624,6 +53654,22 @@ ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
return true;
}
+/* Address space support.
+
+ This is not "far pointers" in the 16-bit sense, but an easy way
+ to use %fs and %gs segment prefixes. Therefore:
+
+ (a) All address spaces have the same modes,
+ (b) All address spaces have the same addresss forms,
+ (c) While %fs and %gs are technically subsets of the generic
+ address space, they are probably not subsets of each other.
+ (d) Since we have no access to the segment base register values
+ without resorting to a system call, we cannot convert a
+ non-default address space to a default address space.
+ Therefore we do not claim %fs or %gs are subsets of generic.
+
+ Therefore, we need not override any of the address space hooks. */
+
/* Initialize the GCC target structure. */
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler "movl\[ \t\]%gs:\\((%eax|%rax)\\), %eax" } } */
+
+extern __seg_gs int *call_me (void);
+
+int
+read_seg_gs (void)
+{
+ return *call_me();
+}