aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2015-11-09 01:20:21 -0800
committerRichard Henderson <rth@gcc.gnu.org>2015-11-09 01:20:21 -0800
commit00402c9415a04840f2f1b08b001ff761fd2a40fc (patch)
treec3e9b3591e6708bd300d869bbfb7bda737b90b37
parent16734677674ae7f58f4339fa97a91411a347e5db (diff)
downloadgcc-00402c9415a04840f2f1b08b001ff761fd2a40fc.zip
gcc-00402c9415a04840f2f1b08b001ff761fd2a40fc.tar.gz
gcc-00402c9415a04840f2f1b08b001ff761fd2a40fc.tar.bz2
i386: Add address spaces for fs/gs segments and tls
* 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
-rw-r--r--gcc/ChangeLog29
-rw-r--r--gcc/config/i386/i386-c.c8
-rw-r--r--gcc/config/i386/i386-protos.h7
-rw-r--r--gcc/config/i386/i386.c246
-rw-r--r--gcc/config/i386/i386.h3
-rw-r--r--gcc/config/i386/predicates.md8
-rw-r--r--gcc/config/i386/rdos.h2
-rw-r--r--gcc/doc/extend.texi47
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.target/i386/addr-space-1.c11
-rw-r--r--gcc/testsuite/gcc.target/i386/addr-space-2.c11
-rw-r--r--gcc/testsuite/gcc.target/i386/addr-space-3.c10
12 files changed, 307 insertions, 81 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c7e5728..d0b119f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index a3c0342..e3a3012 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -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");
}
@@ -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
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 5e46833..026b778 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -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;
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 159e1d1..0d84cde 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index be96c75..3d5b2b2 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -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. */
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 1595142..c11f2d7 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -974,7 +974,7 @@
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
@@ -988,7 +988,7 @@
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). */
@@ -1032,7 +1032,7 @@
if (parts.index && parts.base)
return false;
- if (parts.seg != SEG_DEFAULT)
+ if (parts.seg != ADDR_SPACE_GENERIC)
return false;
/* Do not support (%rip). */
@@ -1064,7 +1064,7 @@
if (parts.index)
return false;
- if (parts.seg != SEG_DEFAULT)
+ if (parts.seg != ADDR_SPACE_GENERIC)
return false;
/* Do not support (%rip). */
diff --git a/gcc/config/i386/rdos.h b/gcc/config/i386/rdos.h
index f9bfe6d..ccf6b78 100644
--- a/gcc/config/i386/rdos.h
+++ b/gcc/config/i386/rdos.h
@@ -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
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 08d4420..aab6bad 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f8c5d5a..c6fe297 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
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();
+}
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
index 0000000..d5c24b6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/addr-space-2.c
@@ -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
index 0000000..63f1f03
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/addr-space-3.c
@@ -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("");
+}