i386: Add address spaces for fs/gs segments and tls
authorRichard Henderson <rth@redhat.com>
Mon, 9 Nov 2015 09:20:21 +0000 (01:20 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 9 Nov 2015 09:20:21 +0000 (01:20 -0800)
        * config/i386/i386-c.c (ix86_target_macros): Define __SEG_FS,
        __SEG_GS, __SEG_TLS.
        (ix86_register_pragmas): Register address spaces __seg_fs,
        __seg_gs, __seg_tls.
        * config/i386/i386-protos.h (enum ix86_address_seg): Remove.
        (ADDR_SPACE_SEG_FS, ADDR_SPACE_SEG_GS, ADDR_SPACE_SEG_TLS): New.
        (struct ix86_address): Use addr_space_t instead of ix86_address_seg.
        * config/i386/i386.c (ix86_decompose_address): Likewise.
        (ix86_legitimate_address_p): Likewise.
        (memory_address_length): Likewise.  Check mem address space too.
        (ix86_print_operand): Use ix86_print_operand_address_as.
        (ix86_print_operand_address_as): Rename from
        ix86_print_operand_address, add new addr_space_t parameter.
        Validate that either the parameter or the ix86_address segment
        is default address space.  Handle ADDR_SPACE_SEG_TLS.
        (ix86_print_operand_address): New.
        (ix86_addr_space_subset_p, TARGET_ADDR_SPACE_SUBSET_P): New.
        (ix86_addr_space_convert, TARGET_ADDR_SPACE_CONVERT): New.
        (ix86_addr_space_debug, TARGET_ADDR_SPACE_DEBUG): New.
        (ix86_addr_space_zero_address_valid): New.
        (TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID): New.
        * config/i386/i386.h (DEFAULT_TLS_SEG_REG): Use addr_space_t constants.
        * config/i386/rdos.h (DEFAULT_TLS_SEG_REG): Likewise.
        * config/i386/predicates.md (address_no_seg_operand): Likewise.
        (vsib_address_operand): Likewise.
        (address_mpx_no_base_operand): Likewise.
        (address_mpx_no_index_operand): Likewise.
        * doc/extend.texi (x86 Named Address Spaces): New section.

        * gcc.target/i386/addr-space-1.c: New test.
        * gcc.target/i386/addr-space-2.c: New test.
        * gcc.target/i386/addr-space-3.c: New test.

From-SVN: r230003

12 files changed:
gcc/ChangeLog
gcc/config/i386/i386-c.c
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/predicates.md
gcc/config/i386/rdos.h
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/addr-space-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/addr-space-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/addr-space-3.c [new file with mode: 0644]

index c7e5728d29ff3ba1d3b9ded662d35e9905c2896f..d0b119f0c5b3c4dbd9ee510635d87835cff74131 100644 (file)
@@ -1,5 +1,34 @@
 2015-11-09  Richard Henderson  <rth@redhat.com>
 
+       * config/i386/i386-c.c (ix86_target_macros): Define __SEG_FS,
+       __SEG_GS, __SEG_TLS.
+       (ix86_register_pragmas): Register address spaces __seg_fs,
+       __seg_gs, __seg_tls.
+       * config/i386/i386-protos.h (enum ix86_address_seg): Remove.
+       (ADDR_SPACE_SEG_FS, ADDR_SPACE_SEG_GS, ADDR_SPACE_SEG_TLS): New.
+       (struct ix86_address): Use addr_space_t instead of ix86_address_seg.
+       * config/i386/i386.c (ix86_decompose_address): Likewise.
+       (ix86_legitimate_address_p): Likewise.
+       (memory_address_length): Likewise.  Check mem address space too.
+       (ix86_print_operand): Use ix86_print_operand_address_as.
+       (ix86_print_operand_address_as): Rename from
+       ix86_print_operand_address, add new addr_space_t parameter.
+       Validate that either the parameter or the ix86_address segment
+       is default address space.  Handle ADDR_SPACE_SEG_TLS.
+       (ix86_print_operand_address): New.
+       (ix86_addr_space_subset_p, TARGET_ADDR_SPACE_SUBSET_P): New.
+       (ix86_addr_space_convert, TARGET_ADDR_SPACE_CONVERT): New.
+       (ix86_addr_space_debug, TARGET_ADDR_SPACE_DEBUG): New.
+       (ix86_addr_space_zero_address_valid): New.
+       (TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID): New.
+       * config/i386/i386.h (DEFAULT_TLS_SEG_REG): Use addr_space_t constants.
+       * config/i386/rdos.h (DEFAULT_TLS_SEG_REG): Likewise.
+       * config/i386/predicates.md (address_no_seg_operand): Likewise.
+       (vsib_address_operand): Likewise.
+       (address_mpx_no_base_operand): Likewise.
+       (address_mpx_no_index_operand): Likewise.
+       * doc/extend.texi (x86 Named Address Spaces): New section.
+
        * config/i386/i386.c (ix86_check_no_addr_space): New.
        (decide_alg): Add have_as parameter.
        (alg_usable_p): Likewise; disable rep algorithms if set.
index a3c0342950dc13f618982f009c2ff58cc4640d5f..e3a301205e612cb7a4807f9196b32750c6550c62 100644 (file)
@@ -586,6 +586,10 @@ ix86_target_macros (void)
                               ix86_tune,
                               ix86_fpmath,
                               cpp_define);
+
+  cpp_define (parse_in, "__SEG_FS");
+  cpp_define (parse_in, "__SEG_GS");
+  cpp_define (parse_in, "__SEG_TLS");
 }
 
 \f
@@ -600,6 +604,10 @@ 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);
+  c_register_addr_space ("__seg_tls", ADDR_SPACE_SEG_TLS);
+
 #ifdef REGISTER_SUBTARGET_PRAGMAS
   REGISTER_SUBTARGET_PRAGMAS ();
 #endif
index 5e46833ff3a82d46c52f50ebfc7c0514afa0e397..026b778f4e398e45c6d1f7cf60ecf94fcd4824c6 100644 (file)
@@ -279,12 +279,11 @@ extern rtx maybe_get_pool_constant (rtx);
 extern char internal_label_prefix[16];
 extern int internal_label_prefix_len;
 
-enum ix86_address_seg { SEG_DEFAULT, SEG_FS, SEG_GS };
 struct ix86_address
 {
   rtx base, index, disp;
   HOST_WIDE_INT scale;
-  enum ix86_address_seg seg;
+  addr_space_t seg;
 };
 
 extern int ix86_decompose_address (rtx, struct ix86_address *);
@@ -326,3 +325,7 @@ 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;
+const addr_space_t ADDR_SPACE_SEG_TLS = 3;
index 159e1d19a10ba7de81a6bb4155e35af0d958505b..0d84cde9cbe97431d73a42faacdd6aacfda5da96 100644 (file)
@@ -80,6 +80,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)
@@ -13988,7 +13989,7 @@ ix86_decompose_address (rtx addr, struct ix86_address *out)
   rtx scale_rtx = NULL_RTX;
   rtx tmp;
   int retval = 1;
-  enum ix86_address_seg seg = SEG_DEFAULT;
+  addr_space_t seg = ADDR_SPACE_GENERIC;
 
   /* Allow zero-extended SImode addresses,
      they will be emitted with addr32 prefix.  */
@@ -14087,7 +14088,7 @@ ix86_decompose_address (rtx addr, struct ix86_address *out)
            case UNSPEC:
              if (XINT (op, 1) == UNSPEC_TP
                  && TARGET_TLS_DIRECT_SEG_REFS
-                 && seg == SEG_DEFAULT)
+                 && seg == ADDR_SPACE_GENERIC)
                seg = DEFAULT_TLS_SEG_REG;
              else
                return 0;
@@ -14675,7 +14676,7 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict)
   struct ix86_address parts;
   rtx base, index, disp;
   HOST_WIDE_INT scale;
-  enum ix86_address_seg seg;
+  addr_space_t seg;
 
   if (ix86_decompose_address (addr, &parts) <= 0)
     /* Decomposition failed.  */
@@ -14721,7 +14722,7 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict)
     return false;
 
   /* Address override works only on the (%reg) part of %fs:(%reg).  */
-  if (seg != SEG_DEFAULT
+  if (seg != ADDR_SPACE_GENERIC
       && ((base && GET_MODE (base) != word_mode)
          || (index && GET_MODE (index) != word_mode)))
     return false;
@@ -17128,32 +17129,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;
+       }
 
-         /* Check for explicit size override (codes 'b', 'w', 'k',
-            'q' and 'x')  */
+      /* 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.  */
          if (code == 'b')
            size = "BYTE";
          else if (code == 'w')
@@ -17164,20 +17155,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)
@@ -17262,7 +17272,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;
@@ -17315,18 +17325,24 @@ 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_TLS)
+       as = DEFAULT_TLS_SEG_REG;
+      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.  */
@@ -17350,7 +17366,7 @@ ix86_print_operand_address (FILE *file, rtx addr)
 
       if (CONST_INT_P (disp))
        {
-         if (ASSEMBLER_DIALECT == ASM_INTEL && parts.seg == SEG_DEFAULT)
+         if (ASSEMBLER_DIALECT == ASM_INTEL && parts.seg == ADDR_SPACE_GENERIC)
            fputs ("ds:", file);
          fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp));
        }
@@ -17486,6 +17502,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
@@ -27136,7 +27158,7 @@ memory_address_length (rtx addr, bool lea)
   ok = ix86_decompose_address (addr, &parts);
   gcc_assert (ok);
 
-  len = (parts.seg == SEG_DEFAULT) ? 0 : 1;
+  len = (parts.seg == ADDR_SPACE_GENERIC) ? 0 : 1;
 
   /*  If this is not LEA instruction, add the length of addr32 prefix.  */
   if (TARGET_64BIT && !lea
@@ -27297,25 +27319,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;
 }
 
@@ -53669,6 +53701,78 @@ 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.
+    (e) However, __seg_tls uses UNSPEC_TP as the base (which itself is
+       stored at __seg_tls:0) so we can map between tls and generic.  */
+
+static bool
+ix86_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
+{
+    return (subset == superset
+           || (superset == ADDR_SPACE_GENERIC
+               && subset == ADDR_SPACE_SEG_TLS));
+}
+#undef TARGET_ADDR_SPACE_SUBSET_P
+#define TARGET_ADDR_SPACE_SUBSET_P ix86_addr_space_subset_p
+
+static rtx
+ix86_addr_space_convert (rtx op, tree from_type, tree to_type)
+{
+  addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
+  addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
+
+  /* Conversion between SEG_TLS and GENERIC is handled by adding or
+     subtracting the thread pointer.  */
+  if ((from_as == ADDR_SPACE_GENERIC && to_as == ADDR_SPACE_SEG_TLS)
+      || (from_as == ADDR_SPACE_SEG_TLS && to_as == ADDR_SPACE_GENERIC))
+    {
+      machine_mode mode = GET_MODE (op);
+      if (mode == VOIDmode)
+       mode = ptr_mode;
+      rtx tp = get_thread_pointer (mode, optimize || mode != ptr_mode);
+      return expand_binop (mode, (to_as == ADDR_SPACE_GENERIC
+                                 ? add_optab : sub_optab),
+                          op, tp, NULL, 1, OPTAB_WIDEN);
+    }
+
+  return op;
+}
+#undef TARGET_ADDR_SPACE_CONVERT
+#define TARGET_ADDR_SPACE_CONVERT ix86_addr_space_convert
+
+static int
+ix86_addr_space_debug (addr_space_t as)
+{
+  /* Fold __seg_tls to __seg_fs or __seg_gs for debugging.  */
+  if (as == ADDR_SPACE_SEG_TLS)
+    as = DEFAULT_TLS_SEG_REG;
+  return as;
+}
+#undef TARGET_ADDR_SPACE_DEBUG
+#define TARGET_ADDR_SPACE_DEBUG ix86_addr_space_debug
+
+/* All use of segmentation is assumed to make address 0 valid.  */
+
+static bool
+ix86_addr_space_zero_address_valid (addr_space_t as)
+{
+  return as != ADDR_SPACE_GENERIC;
+}
+#undef TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID
+#define TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID ix86_addr_space_zero_address_valid
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
index be96c75df77a9ca51e2c7df2d26529b8b2399168..3d5b2b25ced64b558f5f4e82424f079799488250 100644 (file)
@@ -602,7 +602,8 @@ extern tree x86_mfence;
 #define DEFAULT_ABI SYSV_ABI
 
 /* The default TLS segment register used by target.  */
-#define DEFAULT_TLS_SEG_REG (TARGET_64BIT ? SEG_FS : SEG_GS)
+#define DEFAULT_TLS_SEG_REG \
+  (TARGET_64BIT ? ADDR_SPACE_SEG_FS : ADDR_SPACE_SEG_GS)
 
 /* Subtargets may reset this to 1 in order to enable 96-bit long double
    with the rounding mode forced to 53 bits.  */
index 1595142255da8d264e1606503327cf72f5e70a8d..c11f2d7d228e0a6b9e743ffa4797084ff452bcd2 100644 (file)
 
   ok = ix86_decompose_address (op, &parts);
   gcc_assert (ok);
-  return parts.seg == SEG_DEFAULT;
+  return parts.seg == ADDR_SPACE_GENERIC;
 })
 
 ;; Return true if op if a valid base register, displacement or
 
   ok = ix86_decompose_address (op, &parts);
   gcc_assert (ok);
-  if (parts.index || parts.seg != SEG_DEFAULT)
+  if (parts.index || parts.seg != ADDR_SPACE_GENERIC)
     return false;
 
   /* VSIB addressing doesn't support (%rip).  */
   if (parts.index && parts.base)
     return false;
 
-  if (parts.seg != SEG_DEFAULT)
+  if (parts.seg != ADDR_SPACE_GENERIC)
     return false;
 
   /* Do not support (%rip).  */
   if (parts.index)
     return false;
 
-  if (parts.seg != SEG_DEFAULT)
+  if (parts.seg != ADDR_SPACE_GENERIC)
     return false;
 
   /* Do not support (%rip).  */
index f9bfe6d02e4439e6b94ec396f8d55fa902cfba3c..ccf6b78824a77518cb4d9d85d816f427affb844a 100644 (file)
@@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT MASK_TLS_DIRECT_SEG_REFS
 
 #undef DEFAULT_TLS_SEG_REG
-#define DEFAULT_TLS_SEG_REG SEG_GS 
+#define DEFAULT_TLS_SEG_REG ADDR_SPACE_SEG_GS
 
 #undef TARGET_RDOS
 #define TARGET_RDOS 1
index 08d442018ebb8bdf173f16755af2cb59ca4fb3e1..aab6bad905c182966661a3de1c65c0977d01b3a0 100644 (file)
@@ -1261,8 +1261,8 @@ As an extension, GNU C supports named address spaces as
 defined in the N1275 draft of ISO/IEC DTR 18037.  Support for named
 address spaces in GCC will evolve as the draft technical report
 changes.  Calling conventions for any target might also change.  At
-present, only the AVR, SPU, M32C, and RL78 targets support address
-spaces other than the generic address space.
+present, only the AVR, SPU, M32C, RL78, and x86 targets support
+address spaces other than the generic address space.
 
 Address space identifiers may be used exactly like any other C type
 qualifier (e.g., @code{const} or @code{volatile}).  See the N1275
@@ -1451,6 +1451,49 @@ It may use runtime library
 support, or generate special machine instructions to access that address
 space.
 
+@subsection x86 Named Address Spaces
+@cindex x86 named address spaces
+
+On the x86 target, variables may be declared as being relative
+to the @code{%fs} or @code{%gs} segments.
+
+@table @code
+@item __seg_fs
+@itemx __seg_gs
+@cindex @code{__seg_fs} x86 named address space
+@cindex @code{__seg_gs} x86 named address space
+The object is accessed with the respective segment override prefix.
+
+The respective segment base must be set via some method specific to
+the operating system.  Rather than require an expensive system call
+to retrieve the segment base, these address spaces are not considered
+to be subspaces of the generic (flat) address space.  This means that
+explicit casts are required to convert pointers between these address
+spaces and the generic address space.  In practice the application
+should cast to @code{uintptr_t} and apply the segment base offset
+that it installed previously.
+
+The preprocessor symbols @code{__SEG_FS} and @code{__SEG_GS} are
+defined when these address spaces are supported.
+
+@item __seg_tls
+@cindex @code{__seg_tls} x86 named address space
+Some operating systems define either the @code{%fs} or @code{%gs}
+segment as the thread-local storage base for each thread.  Objects
+within this address space are accessed with the appropriate
+segment override prefix.
+
+The pointer located at address 0 within the segment contains the
+offset of the segment within the generic address space.  Thus this
+address space is considered a subspace of the generic address space,
+and the known segment offset is applied when converting addresses
+to and from the generic address space.
+
+The preprocessor symbol @code{__SEG_TLS} is defined when this
+address space is supported.
+
+@end table
+
 @node Zero Length
 @section Arrays of Length Zero
 @cindex arrays of length zero
index f8c5d5ab7a38617c163bd33638ad28af01fdbe31..c6fe2972e2db817d8d4d8acb88921741437b766d 100644 (file)
@@ -1,3 +1,9 @@
+2015-11-09  Richard Henderson  <rth@redhat.com>
+
+       * gcc.target/i386/addr-space-1.c: New test.
+       * gcc.target/i386/addr-space-2.c: New test.
+       * gcc.target/i386/addr-space-3.c: New test.
+
 2015-11-08  Steven g. Kargl  <kargl@gcc.gnu.org>
 
        PR fortran/68053
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 (file)
index 0000000..1e13147
--- /dev/null
@@ -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();
+}
diff --git a/gcc/testsuite/gcc.target/i386/addr-space-2.c b/gcc/testsuite/gcc.target/i386/addr-space-2.c
new file mode 100644 (file)
index 0000000..d5c24b6
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+/* { dg-final { scan-assembler "fs:16" } } */
+/* { dg-final { scan-assembler "gs:16" } } */
+
+int test(void)
+{
+  int __seg_fs *f = (int __seg_fs *)16;
+  int __seg_gs *g = (int __seg_gs *)16;
+  return *f + *g;
+}
diff --git a/gcc/testsuite/gcc.target/i386/addr-space-3.c b/gcc/testsuite/gcc.target/i386/addr-space-3.c
new file mode 100644 (file)
index 0000000..63f1f03
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+/* { dg-final { scan-assembler "[fg]s:0" } } */
+
+void test(int *y)
+{
+  int *x = (int __seg_tls *)0;
+  if (x == y)
+    asm("");
+}