* config/i386/i386-protos.h (ADDR_SPACE_SEG_FS): New. (ADDR_SPACE_SEG_GS): New. * config/i386/i386-c.c (ix86_target_macros): Define __SEG_FS and __SEG_GS. (ix86_register_pragmas): Register address spaces. * config/i386/i386.c (ix86_print_operand_address_as): Rename from ix86_print_operand_address; add an addr_space_t parameter. (ix86_print_operand_address): New. (ix86_print_operand): Use ix86_print_operand_address_as. (ix86_attr_length_address_default): Account for segment prefix.
testsuite/ * gcc.target/i386/addr-space-1.c: New test. --- gcc/config/i386/i386-c.c | 6 + gcc/config/i386/i386-protos.h | 3 + gcc/config/i386/i386.c | 176 +++++++++++++++++---------- gcc/testsuite/gcc.target/i386/addr-space-1.c | 11 ++ 4 files changed, 131 insertions(+), 65 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/addr-space-1.c diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c index 9bc063e..e21b947 100644 --- a/gcc/config/i386/i386-c.c +++ b/gcc/config/i386/i386-c.c @@ -592,6 +592,9 @@ ix86_target_macros (void) ix86_tune, ix86_fpmath, cpp_define); + + cpp_define (parse_in, "__SEG_FS"); + cpp_define (parse_in, "__SEG_GS"); } @@ -606,6 +609,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 diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 5e46833..f942ef5 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -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; diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index b12fb2d..8a41f20 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -95,6 +95,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) @@ -17090,32 +17091,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') @@ -17126,20 +17117,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) @@ -17224,7 +17234,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; @@ -17277,18 +17287,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. */ @@ -17447,6 +17461,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 @@ -27214,25 +27234,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; } @@ -53586,6 +53616,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 diff --git a/gcc/testsuite/gcc.target/i386/addr-space-1.c b/gcc/testsuite/gcc.target/i386/addr-space-1.c new file mode 100644 index 0000000..1e13147 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/addr-space-1.c @@ -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(); +} -- 2.4.3