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)
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. */
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;
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. */
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;
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')
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)
/* 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;
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. */
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));
}
}
}
+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
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
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;
}
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
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
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