* 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

Reply via email to