#define m_GENERIC (m_GENERIC32 | m_GENERIC64)
/* Feature tests against the various tunings. */
-unsigned int ix86_tune_features[X86_TUNE_LAST] = {
+unsigned char ix86_tune_features[X86_TUNE_LAST];
+
+/* Feature tests against the various tunings used to create ix86_tune_features
+ based on the processor mask. */
+static unsigned int initial_ix86_tune_features[X86_TUNE_LAST] = {
/* X86_TUNE_USE_LEAVE: Leave does not affect Nocona SPEC2000 results
negatively, so enabling for Generic64 seems like good code size
tradeoff. We can't enable it for 32bit generic because it does not
m_PPRO | m_AMD_MULTIPLE | m_K6_GEODE | m_PENT | m_CORE2 | m_GENERIC,
/* X86_TUNE_USE_BT */
- m_AMD_MULTIPLE,
+ m_AMD_MULTIPLE | m_CORE2 | m_GENERIC,
/* X86_TUNE_USE_INCDEC */
~(m_PENT4 | m_NOCONA | m_GENERIC),
/* X86_TUNE_USE_VECTOR_CONVERTS: Prefer vector packed SSE conversion
from integer to FP. */
m_AMDFAM10,
+
+ /* X86_TUNE_FUSE_CMP_AND_BRANCH: Fuse a compare or test instruction
+ with a subsequent conditional jump instruction into a single
+ compare-and-branch uop. */
+ m_CORE2,
};
/* Feature tests against the various architecture variations. */
-unsigned int ix86_arch_features[X86_ARCH_LAST] = {
+unsigned char ix86_arch_features[X86_ARCH_LAST];
+
+/* Feature tests against the various architecture variations, used to create
+ ix86_arch_features based on the processor mask. */
+static unsigned int initial_ix86_arch_features[X86_ARCH_LAST] = {
/* X86_ARCH_CMOVE: Conditional move was added for pentiumpro. */
~(m_386 | m_486 | m_PENT | m_K6),
extern int ix86_force_align_arg_pointer;
static const char ix86_force_align_arg_pointer_string[] = "force_align_arg_pointer";
+static rtx (*ix86_gen_leave) (void);
+static rtx (*ix86_gen_pop1) (rtx);
+static rtx (*ix86_gen_add3) (rtx, rtx, rtx);
+static rtx (*ix86_gen_sub3) (rtx, rtx, rtx);
+static rtx (*ix86_gen_sub3_carry) (rtx, rtx, rtx, rtx);
+static rtx (*ix86_gen_one_cmpl2) (rtx, rtx);
+static rtx (*ix86_gen_monitor) (rtx, rtx, rtx);
+
/* Preferred alignment for stack boundary in bits. */
unsigned int ix86_preferred_stack_boundary;
/* Values 1-5: see jump.c */
int ix86_branch_cost;
+/* Calling abi specific va_list type nodes. */
+static GTY(()) tree sysv_va_list_type_node;
+static GTY(()) tree ms_va_list_type_node;
+
/* Variables which are this size or smaller are put in the data/bss
or ldata/lbss sections. */
static bool ix86_expand_vector_init_one_nonzero (bool, enum machine_mode,
rtx, rtx, int);
+enum ix86_function_specific_strings
+{
+ IX86_FUNCTION_SPECIFIC_ARCH,
+ IX86_FUNCTION_SPECIFIC_TUNE,
+ IX86_FUNCTION_SPECIFIC_FPMATH,
+ IX86_FUNCTION_SPECIFIC_MAX
+};
+
+static char *ix86_target_string (int, int, const char *, const char *,
+ const char *, bool);
+static void ix86_debug_options (void) ATTRIBUTE_UNUSED;
+static void ix86_function_specific_save (struct cl_target_option *);
+static void ix86_function_specific_restore (struct cl_target_option *);
+static void ix86_function_specific_print (FILE *, int,
+ struct cl_target_option *);
+static bool ix86_valid_option_attribute_p (tree, tree, tree, int);
+static bool ix86_valid_option_attribute_inner_p (tree, char *[]);
+static bool ix86_can_inline_p (tree, tree);
+static void ix86_set_current_function (tree);
+
\f
/* The svr4 ABI for the i386 says that records and unions are returned
in memory. */
#define DEFAULT_PCC_STRUCT_RETURN 1
#endif
+/* Whether -mtune= or -march= were specified */
+static int ix86_tune_defaulted;
+static int ix86_arch_specified;
+
/* Bit flags that specify the ISA we are compiling for. */
int ix86_isa_flags = TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_ISA_DEFAULT;
#define OPTION_MASK_ISA_SSE5_SET \
(OPTION_MASK_ISA_SSE5 | OPTION_MASK_ISA_SSE4A_SET)
+/* AES and PCLMUL need SSE2 because they use xmm registers */
+#define OPTION_MASK_ISA_AES_SET \
+ (OPTION_MASK_ISA_AES | OPTION_MASK_ISA_SSE2_SET)
+#define OPTION_MASK_ISA_PCLMUL_SET \
+ (OPTION_MASK_ISA_PCLMUL | OPTION_MASK_ISA_SSE2_SET)
+
+#define OPTION_MASK_ISA_ABM_SET \
+ (OPTION_MASK_ISA_ABM | OPTION_MASK_ISA_POPCNT)
+#define OPTION_MASK_ISA_POPCNT_SET OPTION_MASK_ISA_POPCNT
+#define OPTION_MASK_ISA_CX16_SET OPTION_MASK_ISA_CX16
+#define OPTION_MASK_ISA_SAHF_SET OPTION_MASK_ISA_SAHF
+
/* Define a set of ISAs which aren't available when a given ISA is
disabled. MMX and SSE ISAs are handled separately. */
#define OPTION_MASK_ISA_SSE4A_UNSET \
(OPTION_MASK_ISA_SSE4A | OPTION_MASK_ISA_SSE5_UNSET)
-
#define OPTION_MASK_ISA_SSE5_UNSET OPTION_MASK_ISA_SSE5
+#define OPTION_MASK_ISA_AES_UNSET OPTION_MASK_ISA_AES
+#define OPTION_MASK_ISA_PCLMUL_UNSET OPTION_MASK_ISA_PCLMUL
+#define OPTION_MASK_ISA_ABM_UNSET OPTION_MASK_ISA_ABM
+#define OPTION_MASK_ISA_POPCNT_UNSET OPTION_MASK_ISA_POPCNT
+#define OPTION_MASK_ISA_CX16_UNSET OPTION_MASK_ISA_CX16
+#define OPTION_MASK_ISA_SAHF_UNSET OPTION_MASK_ISA_SAHF
/* Vectorization library interface and handlers. */
tree (*ix86_veclib_handler)(enum built_in_function, tree, tree) = NULL;
static tree ix86_veclibabi_svml (enum built_in_function, tree, tree);
static tree ix86_veclibabi_acml (enum built_in_function, tree, tree);
+/* Processor target table, indexed by processor number */
+struct ptt
+{
+ const struct processor_costs *cost; /* Processor costs */
+ const int align_loop; /* Default alignments. */
+ const int align_loop_max_skip;
+ const int align_jump;
+ const int align_jump_max_skip;
+ const int align_func;
+};
+
+static const struct ptt processor_target_table[PROCESSOR_max] =
+{
+ {&i386_cost, 4, 3, 4, 3, 4},
+ {&i486_cost, 16, 15, 16, 15, 16},
+ {&pentium_cost, 16, 7, 16, 7, 16},
+ {&pentiumpro_cost, 16, 15, 16, 10, 16},
+ {&geode_cost, 0, 0, 0, 0, 0},
+ {&k6_cost, 32, 7, 32, 7, 32},
+ {&athlon_cost, 16, 7, 16, 7, 16},
+ {&pentium4_cost, 0, 0, 0, 0, 0},
+ {&k8_cost, 16, 7, 16, 7, 16},
+ {&nocona_cost, 0, 0, 0, 0, 0},
+ {&core2_cost, 16, 10, 16, 10, 16},
+ {&generic32_cost, 16, 7, 16, 7, 16},
+ {&generic64_cost, 16, 10, 16, 10, 16},
+ {&amdfam10_cost, 32, 24, 32, 7, 32}
+};
+
+static const char *const cpu_names[TARGET_CPU_DEFAULT_max] =
+{
+ "generic",
+ "i386",
+ "i486",
+ "pentium",
+ "pentium-mmx",
+ "pentiumpro",
+ "pentium2",
+ "pentium3",
+ "pentium4",
+ "pentium-m",
+ "prescott",
+ "nocona",
+ "core2",
+ "geode",
+ "k6",
+ "k6-2",
+ "k6-3",
+ "athlon",
+ "athlon-4",
+ "k8",
+ "amdfam10"
+};
+\f
/* Implement TARGET_HANDLE_OPTION. */
static bool
}
return true;
+ case OPT_mabm:
+ if (value)
+ {
+ ix86_isa_flags |= OPTION_MASK_ISA_ABM_SET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_ABM_SET;
+ }
+ else
+ {
+ ix86_isa_flags &= ~OPTION_MASK_ISA_ABM_UNSET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_ABM_UNSET;
+ }
+ return true;
+
+ case OPT_mpopcnt:
+ if (value)
+ {
+ ix86_isa_flags |= OPTION_MASK_ISA_POPCNT_SET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_POPCNT_SET;
+ }
+ else
+ {
+ ix86_isa_flags &= ~OPTION_MASK_ISA_POPCNT_UNSET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_POPCNT_UNSET;
+ }
+ return true;
+
+ case OPT_msahf:
+ if (value)
+ {
+ ix86_isa_flags |= OPTION_MASK_ISA_SAHF_SET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_SAHF_SET;
+ }
+ else
+ {
+ ix86_isa_flags &= ~OPTION_MASK_ISA_SAHF_UNSET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_SAHF_UNSET;
+ }
+ return true;
+
+ case OPT_mcx16:
+ if (value)
+ {
+ ix86_isa_flags |= OPTION_MASK_ISA_CX16_SET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_CX16_SET;
+ }
+ else
+ {
+ ix86_isa_flags &= ~OPTION_MASK_ISA_CX16_UNSET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_CX16_UNSET;
+ }
+ return true;
+
+ case OPT_maes:
+ if (value)
+ {
+ ix86_isa_flags |= OPTION_MASK_ISA_AES_SET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_AES_SET;
+ }
+ else
+ {
+ ix86_isa_flags &= ~OPTION_MASK_ISA_AES_UNSET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_AES_UNSET;
+ }
+ return true;
+
+ case OPT_mpclmul:
+ if (value)
+ {
+ ix86_isa_flags |= OPTION_MASK_ISA_PCLMUL_SET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_PCLMUL_SET;
+ }
+ else
+ {
+ ix86_isa_flags &= ~OPTION_MASK_ISA_PCLMUL_UNSET;
+ ix86_isa_flags_explicit |= OPTION_MASK_ISA_PCLMUL_UNSET;
+ }
+ return true;
+
default:
return true;
}
}
+\f
+/* Return a string the documents the current -m options. The caller is
+ responsible for freeing the string. */
+
+static char *
+ix86_target_string (int isa, int flags, const char *arch, const char *tune,
+ const char *fpmath, bool add_nl_p)
+{
+ struct ix86_target_opts
+ {
+ const char *option; /* option string */
+ int mask; /* isa mask options */
+ };
+
+ /* This table is ordered so that options like -msse5 or -msse4.2 that imply
+ preceding options while match those first. */
+ static struct ix86_target_opts isa_opts[] =
+ {
+ { "-m64", OPTION_MASK_ISA_64BIT },
+ { "-msse5", OPTION_MASK_ISA_SSE5 },
+ { "-msse4a", OPTION_MASK_ISA_SSE4A },
+ { "-msse4.2", OPTION_MASK_ISA_SSE4_2 },
+ { "-msse4.1", OPTION_MASK_ISA_SSE4_1 },
+ { "-mssse3", OPTION_MASK_ISA_SSSE3 },
+ { "-msse3", OPTION_MASK_ISA_SSE3 },
+ { "-msse2", OPTION_MASK_ISA_SSE2 },
+ { "-msse", OPTION_MASK_ISA_SSE },
+ { "-m3dnow", OPTION_MASK_ISA_3DNOW },
+ { "-mmmx", OPTION_MASK_ISA_MMX },
+ { "-mabm", OPTION_MASK_ISA_ABM },
+ { "-mpopcnt", OPTION_MASK_ISA_POPCNT },
+ { "-maes", OPTION_MASK_ISA_AES },
+ { "-mpclmul", OPTION_MASK_ISA_PCLMUL },
+ };
+
+ /* Flag options. */
+ static struct ix86_target_opts flag_opts[] =
+ {
+ { "-m128bit-long-double", MASK_128BIT_LONG_DOUBLE },
+ { "-m80387", MASK_80387 },
+ { "-maccumulate-outgoing-args", MASK_ACCUMULATE_OUTGOING_ARGS },
+ { "-malign-double", MASK_ALIGN_DOUBLE },
+ { "-mcld", MASK_CLD },
+ { "-mfp-ret-in-387", MASK_FLOAT_RETURNS },
+ { "-mieee-fp", MASK_IEEE_FP },
+ { "-minline-all-stringops", MASK_INLINE_ALL_STRINGOPS },
+ { "-minline-stringops-dynamically", MASK_INLINE_STRINGOPS_DYNAMICALLY },
+ { "-mms-bitfields", MASK_MS_BITFIELD_LAYOUT },
+ { "-mno-align-stringops", MASK_NO_ALIGN_STRINGOPS },
+ { "-mno-fancy-math-387", MASK_NO_FANCY_MATH_387 },
+ { "-mno-fused-madd", MASK_NO_FUSED_MADD },
+ { "-mno-push-args", MASK_NO_PUSH_ARGS },
+ { "-mno-red-zone", MASK_NO_RED_ZONE },
+ { "-momit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER },
+ { "-mrecip", MASK_RECIP },
+ { "-mrtd", MASK_RTD },
+ { "-msseregparm", MASK_SSEREGPARM },
+ { "-mstack-arg-probe", MASK_STACK_PROBE },
+ { "-mtls-direct-seg-refs", MASK_TLS_DIRECT_SEG_REFS },
+ };
+
+ const char *opts[ (sizeof (isa_opts) / sizeof (isa_opts[0])
+ + sizeof (flag_opts) / sizeof (flag_opts[0])
+ + 6)][2];
+
+ char isa_other[40];
+ char target_other[40];
+ unsigned num = 0;
+ unsigned i, j;
+ char *ret;
+ char *ptr;
+ size_t len;
+ size_t line_len;
+ size_t sep_len;
+
+ memset (opts, '\0', sizeof (opts));
+
+ /* Add -march= option. */
+ if (arch)
+ {
+ opts[num][0] = "-march=";
+ opts[num++][1] = arch;
+ }
+
+ /* Add -mtune= option. */
+ if (tune)
+ {
+ opts[num][0] = "-mtune=";
+ opts[num++][1] = tune;
+ }
+
+ /* Pick out the options in isa options. */
+ for (i = 0; i < sizeof (isa_opts) / sizeof (isa_opts[0]); i++)
+ {
+ if ((isa & isa_opts[i].mask) != 0)
+ {
+ opts[num++][0] = isa_opts[i].option;
+ isa &= ~ isa_opts[i].mask;
+ }
+ }
+
+ if (isa && add_nl_p)
+ {
+ opts[num++][0] = isa_other;
+ sprintf (isa_other, "(other isa: 0x%x)", isa);
+ }
+
+ /* Add flag options. */
+ for (i = 0; i < sizeof (flag_opts) / sizeof (flag_opts[0]); i++)
+ {
+ if ((flags & flag_opts[i].mask) != 0)
+ {
+ opts[num++][0] = flag_opts[i].option;
+ flags &= ~ flag_opts[i].mask;
+ }
+ }
+
+ if (flags && add_nl_p)
+ {
+ opts[num++][0] = target_other;
+ sprintf (target_other, "(other flags: 0x%x)", isa);
+ }
+
+ /* Add -fpmath= option. */
+ if (fpmath)
+ {
+ opts[num][0] = "-mfpmath=";
+ opts[num++][1] = fpmath;
+ }
+
+ /* Any options? */
+ if (num == 0)
+ return NULL;
+
+ gcc_assert (num < sizeof (opts) / sizeof (opts[0]));
+
+ /* Size the string. */
+ len = 0;
+ sep_len = (add_nl_p) ? 3 : 1;
+ for (i = 0; i < num; i++)
+ {
+ len += sep_len;
+ for (j = 0; j < 2; j++)
+ if (opts[i][j])
+ len += strlen (opts[i][j]);
+ }
+
+ /* Build the string. */
+ ret = ptr = (char *) xmalloc (len);
+ line_len = 0;
+
+ for (i = 0; i < num; i++)
+ {
+ size_t len2[2];
+
+ for (j = 0; j < 2; j++)
+ len2[j] = (opts[i][j]) ? strlen (opts[i][j]) : 0;
+
+ if (i != 0)
+ {
+ *ptr++ = ' ';
+ line_len++;
+
+ if (add_nl_p && line_len + len2[0] + len2[1] > 70)
+ {
+ *ptr++ = '\\';
+ *ptr++ = '\n';
+ line_len = 0;
+ }
+ }
+
+ for (j = 0; j < 2; j++)
+ if (opts[i][j])
+ {
+ memcpy (ptr, opts[i][j], len2[j]);
+ ptr += len2[j];
+ line_len += len2[j];
+ }
+ }
+
+ *ptr = '\0';
+ gcc_assert (ret + len >= ptr);
+
+ return ret;
+}
+
+/* Function that is callable from the debugger to print the current
+ options. */
+void
+ix86_debug_options (void)
+{
+ char *opts = ix86_target_string (ix86_isa_flags, target_flags,
+ ix86_arch_string, ix86_tune_string,
+ ix86_fpmath_string, true);
+
+ if (opts)
+ {
+ fprintf (stderr, "%s\n\n", opts);
+ free (opts);
+ }
+ else
+ fprintf (stderr, "<no options>\n\n");
+ return;
+}
+\f
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
`OVERRIDE_OPTIONS' to take account of this. This macro, if
`-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
void
-override_options (void)
+override_options (bool main_args_p)
{
int i;
- int ix86_tune_defaulted = 0;
- int ix86_arch_specified = 0;
unsigned int ix86_arch_mask, ix86_tune_mask;
+ const char *prefix;
+ const char *suffix;
+ const char *sw;
/* Comes from final.c -- no real reason to change it. */
#define MAX_CODE_ALIGN 16
- static struct ptt
- {
- const struct processor_costs *cost; /* Processor costs */
- const int align_loop; /* Default alignments. */
- const int align_loop_max_skip;
- const int align_jump;
- const int align_jump_max_skip;
- const int align_func;
- }
- const processor_target_table[PROCESSOR_max] =
- {
- {&i386_cost, 4, 3, 4, 3, 4},
- {&i486_cost, 16, 15, 16, 15, 16},
- {&pentium_cost, 16, 7, 16, 7, 16},
- {&pentiumpro_cost, 16, 15, 16, 10, 16},
- {&geode_cost, 0, 0, 0, 0, 0},
- {&k6_cost, 32, 7, 32, 7, 32},
- {&athlon_cost, 16, 7, 16, 7, 16},
- {&pentium4_cost, 0, 0, 0, 0, 0},
- {&k8_cost, 16, 7, 16, 7, 16},
- {&nocona_cost, 0, 0, 0, 0, 0},
- {&core2_cost, 16, 10, 16, 10, 16},
- {&generic32_cost, 16, 7, 16, 7, 16},
- {&generic64_cost, 16, 10, 16, 10, 16},
- {&amdfam10_cost, 32, 24, 32, 7, 32}
- };
-
- static const char *const cpu_names[TARGET_CPU_DEFAULT_max] =
- {
- "generic",
- "i386",
- "i486",
- "pentium",
- "pentium-mmx",
- "pentiumpro",
- "pentium2",
- "pentium3",
- "pentium4",
- "pentium-m",
- "prescott",
- "nocona",
- "core2",
- "geode",
- "k6",
- "k6-2",
- "k6-3",
- "athlon",
- "athlon-4",
- "k8",
- "amdfam10"
- };
-
enum pta_flags
{
PTA_SSE = 1 << 0,
int const pta_size = ARRAY_SIZE (processor_alias_table);
+ /* Set up prefix/suffix so the error messages refer to either the command
+ line argument, or the attribute(option). */
+ if (main_args_p)
+ {
+ prefix = "-m";
+ suffix = "";
+ sw = "switch";
+ }
+ else
+ {
+ prefix = "option(\"";
+ suffix = "\")";
+ sw = "attribute";
+ }
+
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
else
ix86_tune_string = "generic32";
}
+ /* If this call is for setting the option attribute, allow the
+ generic32/generic64 that was previously set. */
+ else if (!main_args_p
+ && (!strcmp (ix86_tune_string, "generic32")
+ || !strcmp (ix86_tune_string, "generic64")))
+ ;
else if (!strncmp (ix86_tune_string, "generic", 7))
- error ("bad value (%s) for -mtune= switch", ix86_tune_string);
+ error ("bad value (%s) for %stune=%s %s",
+ ix86_tune_string, prefix, suffix, sw);
}
else
{
else if (!strcmp (ix86_stringop_string, "unrolled_loop"))
stringop_alg = unrolled_loop;
else
- error ("bad value (%s) for -mstringop-strategy= switch", ix86_stringop_string);
+ error ("bad value (%s) for %sstringop-strategy=%s %s",
+ ix86_stringop_string, prefix, suffix, sw);
}
if (!strcmp (ix86_tune_string, "x86-64"))
- warning (OPT_Wdeprecated, "-mtune=x86-64 is deprecated. Use -mtune=k8 or "
- "-mtune=generic instead as appropriate.");
+ warning (OPT_Wdeprecated, "%stune=x86-64%s is deprecated. Use "
+ "%stune=k8%s or %stune=generic%s instead as appropriate.",
+ prefix, suffix, prefix, suffix, prefix, suffix);
if (!ix86_arch_string)
ix86_arch_string = TARGET_64BIT ? "x86-64" : "i386";
ix86_arch_specified = 1;
if (!strcmp (ix86_arch_string, "generic"))
- error ("generic CPU can be used only for -mtune= switch");
+ error ("generic CPU can be used only for %stune=%s %s",
+ prefix, suffix, sw);
if (!strncmp (ix86_arch_string, "generic", 7))
- error ("bad value (%s) for -march= switch", ix86_arch_string);
+ error ("bad value (%s) for %sarch=%s %s",
+ ix86_arch_string, prefix, suffix, sw);
if (ix86_cmodel_string != 0)
{
else if (!strcmp (ix86_cmodel_string, "kernel") && !flag_pic)
ix86_cmodel = CM_KERNEL;
else
- error ("bad value (%s) for -mcmodel= switch", ix86_cmodel_string);
+ error ("bad value (%s) for %scmodel=%s %s",
+ ix86_cmodel_string, prefix, suffix, sw);
}
else
{
else if (!strcmp (ix86_asm_string, "att"))
ix86_asm_dialect = ASM_ATT;
else
- error ("bad value (%s) for -masm= switch", ix86_asm_string);
+ error ("bad value (%s) for %sasm=%s %s",
+ ix86_asm_string, prefix, suffix, sw);
}
if ((TARGET_64BIT == 0) != (ix86_cmodel == CM_32))
error ("code model %qs not supported in the %s bit mode",
if (processor_alias_table[i].flags & PTA_SSE5
&& !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE5))
ix86_isa_flags |= OPTION_MASK_ISA_SSE5;
-
- if (processor_alias_table[i].flags & PTA_ABM)
- x86_abm = true;
- if (processor_alias_table[i].flags & PTA_CX16)
- x86_cmpxchg16b = true;
- if (processor_alias_table[i].flags & (PTA_POPCNT | PTA_ABM))
- x86_popcnt = true;
+ if (processor_alias_table[i].flags & PTA_ABM
+ && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_ABM))
+ ix86_isa_flags |= OPTION_MASK_ISA_ABM;
+ if (processor_alias_table[i].flags & PTA_CX16
+ && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_CX16))
+ ix86_isa_flags |= OPTION_MASK_ISA_CX16;
+ if (processor_alias_table[i].flags & (PTA_POPCNT | PTA_ABM)
+ && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_POPCNT))
+ ix86_isa_flags |= OPTION_MASK_ISA_POPCNT;
+ if (!(TARGET_64BIT && (processor_alias_table[i].flags & PTA_NO_SAHF))
+ && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SAHF))
+ ix86_isa_flags |= OPTION_MASK_ISA_SAHF;
+ if (processor_alias_table[i].flags & PTA_AES
+ && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AES))
+ ix86_isa_flags |= OPTION_MASK_ISA_AES;
+ if (processor_alias_table[i].flags & PTA_PCLMUL
+ && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_PCLMUL))
+ ix86_isa_flags |= OPTION_MASK_ISA_PCLMUL;
if (processor_alias_table[i].flags & (PTA_PREFETCH_SSE | PTA_SSE))
x86_prefetch_sse = true;
- if (!(TARGET_64BIT && (processor_alias_table[i].flags & PTA_NO_SAHF)))
- x86_sahf = true;
- if (processor_alias_table[i].flags & PTA_AES)
- x86_aes = true;
- if (processor_alias_table[i].flags & PTA_PCLMUL)
- x86_pclmul = true;
break;
}
if (i == pta_size)
- error ("bad value (%s) for -march= switch", ix86_arch_string);
+ error ("bad value (%s) for %sarch=%s %s",
+ ix86_arch_string, prefix, suffix, sw);
ix86_arch_mask = 1u << ix86_arch;
for (i = 0; i < X86_ARCH_LAST; ++i)
- ix86_arch_features[i] &= ix86_arch_mask;
+ ix86_arch_features[i] = !!(initial_ix86_arch_features[i] & ix86_arch_mask);
for (i = 0; i < pta_size; i++)
if (! strcmp (ix86_tune_string, processor_alias_table[i].name))
break;
}
if (i == pta_size)
- error ("bad value (%s) for -mtune= switch", ix86_tune_string);
-
- /* Enable SSE2 if AES or PCLMUL is enabled. */
- if ((x86_aes || x86_pclmul)
- && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE2))
- {
- ix86_isa_flags |= OPTION_MASK_ISA_SSE2_SET;
- ix86_isa_flags_explicit |= OPTION_MASK_ISA_SSE2_SET;
- }
+ error ("bad value (%s) for %stune=%s %s",
+ ix86_tune_string, prefix, suffix, sw);
ix86_tune_mask = 1u << ix86_tune;
for (i = 0; i < X86_TUNE_LAST; ++i)
- ix86_tune_features[i] &= ix86_tune_mask;
+ ix86_tune_features[i] = !!(initial_ix86_tune_features[i] & ix86_tune_mask);
if (optimize_size)
ix86_cost = &size_cost;
if (ix86_regparm_string)
{
if (TARGET_64BIT)
- warning (0, "-mregparm is ignored in 64-bit mode");
+ warning (0, "%sregparm%s is ignored in 64-bit mode", prefix, suffix);
i = atoi (ix86_regparm_string);
if (i < 0 || i > REGPARM_MAX)
- error ("-mregparm=%d is not between 0 and %d", i, REGPARM_MAX);
+ error ("%sregparm=%d%s is not between 0 and %d",
+ prefix, i, suffix, REGPARM_MAX);
else
ix86_regparm = i;
}
Remove this code in GCC 3.2 or later. */
if (ix86_align_loops_string)
{
- warning (0, "-malign-loops is obsolete, use -falign-loops");
+ warning (0, "%salign-loops%s is obsolete, use %salign-loops%s",
+ prefix, suffix, prefix, suffix);
if (align_loops == 0)
{
i = atoi (ix86_align_loops_string);
if (i < 0 || i > MAX_CODE_ALIGN)
- error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
+ error ("%salign-loops=%d%s is not between 0 and %d",
+ prefix, i, suffix, MAX_CODE_ALIGN);
else
align_loops = 1 << i;
}
if (ix86_align_jumps_string)
{
- warning (0, "-malign-jumps is obsolete, use -falign-jumps");
+ warning (0, "%salign-jumps%s is obsolete, use %salign-jumps%s",
+ prefix, suffix, prefix, suffix);
if (align_jumps == 0)
{
i = atoi (ix86_align_jumps_string);
if (i < 0 || i > MAX_CODE_ALIGN)
- error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
+ error ("%salign-loops=%d%s is not between 0 and %d",
+ prefix, i, suffix, MAX_CODE_ALIGN);
else
align_jumps = 1 << i;
}
if (ix86_align_funcs_string)
{
- warning (0, "-malign-functions is obsolete, use -falign-functions");
+ warning (0, "%salign-functions%s is obsolete, use %salign-functions%s",
+ prefix, suffix, prefix, suffix);
if (align_functions == 0)
{
i = atoi (ix86_align_funcs_string);
if (i < 0 || i > MAX_CODE_ALIGN)
- error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
+ error ("%salign-loops=%d%s is not between 0 and %d",
+ prefix, i, suffix, MAX_CODE_ALIGN);
else
align_functions = 1 << i;
}
{
i = atoi (ix86_branch_cost_string);
if (i < 0 || i > 5)
- error ("-mbranch-cost=%d is not between 0 and 5", i);
+ error ("%sbranch-cost=%d%s is not between 0 and 5", prefix, i, suffix);
else
ix86_branch_cost = i;
}
{
i = atoi (ix86_section_threshold_string);
if (i < 0)
- error ("-mlarge-data-threshold=%d is negative", i);
+ error ("%slarge-data-threshold=%d%s is negative", prefix, i, suffix);
else
ix86_section_threshold = i;
}
else if (strcmp (ix86_tls_dialect_string, "sun") == 0)
ix86_tls_dialect = TLS_DIALECT_SUN;
else
- error ("bad value (%s) for -mtls-dialect= switch",
- ix86_tls_dialect_string);
+ error ("bad value (%s) for %stls-dialect=%s %s",
+ ix86_tls_dialect_string, prefix, suffix, sw);
}
if (ix87_precision_string)
| TARGET_SUBTARGET64_ISA_DEFAULT) & ~ix86_isa_flags_explicit);
if (TARGET_RTD)
- warning (0, "-mrtd is ignored in 64bit mode");
+ warning (0, "%srtd%s is ignored in 64bit mode", prefix, suffix);
}
else
{
/* Turn on popcnt instruction for -msse4.2 or -mabm. */
if (TARGET_SSE4_2 || TARGET_ABM)
- x86_popcnt = true;
+ ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
/* Validate -mpreferred-stack-boundary= value, or provide default.
The default of 128 bits is for Pentium III's SSE __m128. We can't
{
i = atoi (ix86_preferred_stack_boundary_string);
if (i < (TARGET_64BIT ? 4 : 2) || i > 12)
- error ("-mpreferred-stack-boundary=%d is not between %d and 12", i,
- TARGET_64BIT ? 4 : 2);
+ error ("%spreferred-stack-boundary=%d%s is not between %d and 12",
+ prefix, i, suffix, TARGET_64BIT ? 4 : 2);
else
ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
}
/* Accept -msseregparm only if at least SSE support is enabled. */
if (TARGET_SSEREGPARM
&& ! TARGET_SSE)
- error ("-msseregparm used without SSE enabled");
+ error ("%ssseregparm%s used without SSE enabled", prefix, suffix);
ix86_fpmath = TARGET_FPMATH_DEFAULT;
if (ix86_fpmath_string != 0)
ix86_fpmath = FPMATH_SSE;
}
else if (! strcmp (ix86_fpmath_string, "387,sse")
- || ! strcmp (ix86_fpmath_string, "sse,387"))
+ || ! strcmp (ix86_fpmath_string, "387+sse")
+ || ! strcmp (ix86_fpmath_string, "sse,387")
+ || ! strcmp (ix86_fpmath_string, "sse+387")
+ || ! strcmp (ix86_fpmath_string, "both"))
{
if (!TARGET_SSE)
{
ix86_fpmath = (enum fpmath_unit) (FPMATH_SSE | FPMATH_387);
}
else
- error ("bad value (%s) for -mfpmath= switch", ix86_fpmath_string);
+ error ("bad value (%s) for %sfpmath=%s %s",
+ ix86_fpmath_string, prefix, suffix, sw);
}
/* If the i387 is disabled, then do not return values in it. */
ix86_veclib_handler = ix86_veclibabi_acml;
else
error ("unknown vectorization library ABI type (%s) for "
- "-mveclibabi= switch", ix86_veclibabi_string);
+ "%sveclibabi=%s %s", ix86_veclibabi_string,
+ prefix, suffix, sw);
}
if ((x86_accumulate_outgoing_args & ix86_tune_mask)
{
if (target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS)
warning (0, "unwind tables currently require either a frame pointer "
- "or -maccumulate-outgoing-args for correctness");
+ "or %saccumulate-outgoing-args%s for correctness",
+ prefix, suffix);
target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS;
}
&& !(target_flags & MASK_ACCUMULATE_OUTGOING_ARGS))
{
if (target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS)
- warning (0, "stack probing requires -maccumulate-outgoing-args "
- "for correctness");
+ warning (0, "stack probing requires %saccumulate-outgoing-args%s "
+ "for correctness", prefix, suffix);
target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS;
}
+ TARGET_CMOVE = 0;
+
/* For sane SSE instruction set generation we need fcomi instruction.
It is safe to enable all CMOVE instructions. */
if (TARGET_SSE)
set_param_value ("l2-cache-size", ix86_cost->l2_cache_size);
/* If using typedef char *va_list, signal that __builtin_va_start (&ap, 0)
- can be optimized to ap = __builtin_next_arg (0).
- For abi switching it should be corrected. */
- if (!TARGET_64BIT || DEFAULT_ABI == MS_ABI)
+ can be optimized to ap = __builtin_next_arg (0). */
+ if (!TARGET_64BIT)
targetm.expand_builtin_va_start = NULL;
+ if (TARGET_64BIT)
+ {
+ ix86_gen_leave = gen_leave_rex64;
+ ix86_gen_pop1 = gen_popdi1;
+ ix86_gen_add3 = gen_adddi3;
+ ix86_gen_sub3 = gen_subdi3;
+ ix86_gen_sub3_carry = gen_subdi3_carry_rex64;
+ ix86_gen_one_cmpl2 = gen_one_cmpldi2;
+ ix86_gen_monitor = gen_sse3_monitor64;
+ }
+ else
+ {
+ ix86_gen_leave = gen_leave;
+ ix86_gen_pop1 = gen_popsi1;
+ ix86_gen_add3 = gen_addsi3;
+ ix86_gen_sub3 = gen_subsi3;
+ ix86_gen_sub3_carry = gen_subsi3_carry;
+ ix86_gen_one_cmpl2 = gen_one_cmplsi2;
+ ix86_gen_monitor = gen_sse3_monitor;
+ }
+
#ifdef USE_IX86_CLD
/* Use -mcld by default for 32-bit code if configured with --enable-cld. */
if (!TARGET_64BIT)
target_flags |= MASK_CLD & ~target_flags_explicit;
#endif
+
+ /* Save the initial options in case the user does function specific options */
+ if (main_args_p)
+ target_option_default_node = target_option_current_node
+ = build_target_option_node ();
}
\f
+/* Save the current options */
+
+static void
+ix86_function_specific_save (struct cl_target_option *ptr)
+{
+ gcc_assert (IN_RANGE (ix86_arch, 0, 255));
+ gcc_assert (IN_RANGE (ix86_tune, 0, 255));
+ gcc_assert (IN_RANGE (ix86_fpmath, 0, 255));
+ gcc_assert (IN_RANGE (ix86_branch_cost, 0, 255));
+
+ ptr->arch = ix86_arch;
+ ptr->tune = ix86_tune;
+ ptr->fpmath = ix86_fpmath;
+ ptr->branch_cost = ix86_branch_cost;
+ ptr->tune_defaulted = ix86_tune_defaulted;
+ ptr->arch_specified = ix86_arch_specified;
+ ptr->ix86_isa_flags_explicit = ix86_isa_flags_explicit;
+ ptr->target_flags_explicit = target_flags_explicit;
+}
+
+/* Restore the current options */
+
+static void
+ix86_function_specific_restore (struct cl_target_option *ptr)
+{
+ enum processor_type old_tune = ix86_tune;
+ enum processor_type old_arch = ix86_arch;
+ unsigned int ix86_arch_mask, ix86_tune_mask;
+ int i;
+
+ ix86_arch = ptr->arch;
+ ix86_tune = ptr->tune;
+ ix86_fpmath = ptr->fpmath;
+ ix86_branch_cost = ptr->branch_cost;
+ ix86_tune_defaulted = ptr->tune_defaulted;
+ ix86_arch_specified = ptr->arch_specified;
+ ix86_isa_flags_explicit = ptr->ix86_isa_flags_explicit;
+ target_flags_explicit = ptr->target_flags_explicit;
+
+ /* Recreate the arch feature tests if the arch changed */
+ if (old_arch != ix86_arch)
+ {
+ ix86_arch_mask = 1u << ix86_arch;
+ for (i = 0; i < X86_ARCH_LAST; ++i)
+ ix86_arch_features[i]
+ = !!(initial_ix86_arch_features[i] & ix86_arch_mask);
+ }
+
+ /* Recreate the tune optimization tests */
+ if (old_tune != ix86_tune)
+ {
+ ix86_tune_mask = 1u << ix86_tune;
+ for (i = 0; i < X86_TUNE_LAST; ++i)
+ ix86_tune_features[i]
+ = !!(initial_ix86_tune_features[i] & ix86_tune_mask);
+ }
+}
+
+/* Print the current options */
+
+static void
+ix86_function_specific_print (FILE *file, int indent,
+ struct cl_target_option *ptr)
+{
+ char *target_string
+ = ix86_target_string (ptr->ix86_isa_flags, ptr->target_flags,
+ NULL, NULL, NULL, false);
+
+ fprintf (file, "%*sarch = %d (%s)\n",
+ indent, "",
+ ptr->arch,
+ ((ptr->arch < TARGET_CPU_DEFAULT_max)
+ ? cpu_names[ptr->arch]
+ : "<unknown>"));
+
+ fprintf (file, "%*stune = %d (%s)\n",
+ indent, "",
+ ptr->tune,
+ ((ptr->tune < TARGET_CPU_DEFAULT_max)
+ ? cpu_names[ptr->tune]
+ : "<unknown>"));
+
+ fprintf (file, "%*sfpmath = %d%s%s\n", indent, "", ptr->fpmath,
+ (ptr->fpmath & FPMATH_387) ? ", 387" : "",
+ (ptr->fpmath & FPMATH_SSE) ? ", sse" : "");
+ fprintf (file, "%*sbranch_cost = %d\n", indent, "", ptr->branch_cost);
+
+ if (target_string)
+ {
+ fprintf (file, "%*s%s\n", indent, "", target_string);
+ free (target_string);
+ }
+}
+
+\f
+/* Inner function to process the attribute((option(...))), take an argument and
+ set the current options from the argument. If we have a list, recursively go
+ over the list. */
+
+static bool
+ix86_valid_option_attribute_inner_p (tree args, char *p_strings[])
+{
+ char *next_optstr;
+ bool ret = true;
+
+#define IX86_ATTR_ISA(S,O) { S, sizeof (S)-1, ix86_opt_isa, O, 0 }
+#define IX86_ATTR_STR(S,O) { S, sizeof (S)-1, ix86_opt_str, O, 0 }
+#define IX86_ATTR_YES(S,O,M) { S, sizeof (S)-1, ix86_opt_yes, O, M }
+#define IX86_ATTR_NO(S,O,M) { S, sizeof (S)-1, ix86_opt_no, O, M }
+
+ enum ix86_opt_type
+ {
+ ix86_opt_unknown,
+ ix86_opt_yes,
+ ix86_opt_no,
+ ix86_opt_str,
+ ix86_opt_isa
+ };
+
+ static const struct
+ {
+ const char *string;
+ size_t len;
+ enum ix86_opt_type type;
+ int opt;
+ int mask;
+ } attrs[] = {
+ /* isa options */
+ IX86_ATTR_ISA ("3dnow", OPT_m3dnow),
+ IX86_ATTR_ISA ("abm", OPT_mabm),
+ IX86_ATTR_ISA ("aes", OPT_maes),
+ IX86_ATTR_ISA ("mmx", OPT_mmmx),
+ IX86_ATTR_ISA ("pclmul", OPT_mpclmul),
+ IX86_ATTR_ISA ("popcnt", OPT_mpopcnt),
+ IX86_ATTR_ISA ("sse", OPT_msse),
+ IX86_ATTR_ISA ("sse2", OPT_msse2),
+ IX86_ATTR_ISA ("sse3", OPT_msse3),
+ IX86_ATTR_ISA ("sse4", OPT_msse4),
+ IX86_ATTR_ISA ("sse4.1", OPT_msse4_1),
+ IX86_ATTR_ISA ("sse4.2", OPT_msse4_2),
+ IX86_ATTR_ISA ("sse4a", OPT_msse4a),
+ IX86_ATTR_ISA ("sse5", OPT_msse5),
+ IX86_ATTR_ISA ("ssse3", OPT_mssse3),
+
+ /* string options */
+ IX86_ATTR_STR ("arch=", IX86_FUNCTION_SPECIFIC_ARCH),
+ IX86_ATTR_STR ("fpmath=", IX86_FUNCTION_SPECIFIC_FPMATH),
+ IX86_ATTR_STR ("tune=", IX86_FUNCTION_SPECIFIC_TUNE),
+
+ /* flag options */
+ IX86_ATTR_YES ("cld",
+ OPT_mcld,
+ MASK_CLD),
+
+ IX86_ATTR_NO ("fancy-math-387",
+ OPT_mfancy_math_387,
+ MASK_NO_FANCY_MATH_387),
+
+ IX86_ATTR_NO ("fused-madd",
+ OPT_mfused_madd,
+ MASK_NO_FUSED_MADD),
+
+ IX86_ATTR_YES ("ieee-fp",
+ OPT_mieee_fp,
+ MASK_IEEE_FP),
+
+ IX86_ATTR_YES ("inline-all-stringops",
+ OPT_minline_all_stringops,
+ MASK_INLINE_ALL_STRINGOPS),
+
+ IX86_ATTR_YES ("inline-stringops-dynamically",
+ OPT_minline_stringops_dynamically,
+ MASK_INLINE_STRINGOPS_DYNAMICALLY),
+
+ IX86_ATTR_NO ("align-stringops",
+ OPT_mno_align_stringops,
+ MASK_NO_ALIGN_STRINGOPS),
+
+ IX86_ATTR_YES ("recip",
+ OPT_mrecip,
+ MASK_RECIP),
+
+ };
+
+ /* If this is a list, recurse to get the options. */
+ if (TREE_CODE (args) == TREE_LIST)
+ {
+ bool ret = true;
+
+ for (; args; args = TREE_CHAIN (args))
+ if (TREE_VALUE (args)
+ && !ix86_valid_option_attribute_inner_p (TREE_VALUE (args), p_strings))
+ ret = false;
+
+ return ret;
+ }
+
+ else if (TREE_CODE (args) != STRING_CST)
+ gcc_unreachable ();
+
+ /* Handle multiple arguments separated by commas. */
+ next_optstr = ASTRDUP (TREE_STRING_POINTER (args));
+
+ while (next_optstr && *next_optstr != '\0')
+ {
+ char *p = next_optstr;
+ char *orig_p = p;
+ char *comma = strchr (next_optstr, ',');
+ const char *opt_string;
+ size_t len, opt_len;
+ int opt;
+ bool opt_set_p;
+ char ch;
+ unsigned i;
+ enum ix86_opt_type type = ix86_opt_unknown;
+ int mask = 0;
+
+ if (comma)
+ {
+ *comma = '\0';
+ len = comma - next_optstr;
+ next_optstr = comma + 1;
+ }
+ else
+ {
+ len = strlen (p);
+ next_optstr = NULL;
+ }
+
+ /* Recognize no-xxx. */
+ if (len > 3 && p[0] == 'n' && p[1] == 'o' && p[2] == '-')
+ {
+ opt_set_p = false;
+ p += 3;
+ len -= 3;
+ }
+ else
+ opt_set_p = true;
+
+ /* Find the option. */
+ ch = *p;
+ opt = N_OPTS;
+ for (i = 0; i < sizeof (attrs) / sizeof (attrs[0]); i++)
+ {
+ type = attrs[i].type;
+ opt_len = attrs[i].len;
+ if (ch == attrs[i].string[0]
+ && ((type != ix86_opt_str) ? len == opt_len : len > opt_len)
+ && memcmp (p, attrs[i].string, opt_len) == 0)
+ {
+ opt = attrs[i].opt;
+ mask = attrs[i].mask;
+ opt_string = attrs[i].string;
+ break;
+ }
+ }
+
+ /* Process the option. */
+ if (opt == N_OPTS)
+ {
+ error ("attribute(option(\"%s\")) is unknown", orig_p);
+ ret = false;
+ }
+
+ else if (type == ix86_opt_isa)
+ ix86_handle_option (opt, p, opt_set_p);
+
+ else if (type == ix86_opt_yes || type == ix86_opt_no)
+ {
+ if (type == ix86_opt_no)
+ opt_set_p = !opt_set_p;
+
+ if (opt_set_p)
+ target_flags |= mask;
+ else
+ target_flags &= ~mask;
+ }
+
+ else if (type == ix86_opt_str)
+ {
+ if (p_strings[opt])
+ {
+ error ("option(\"%s\") was already specified", opt_string);
+ ret = false;
+ }
+ else
+ p_strings[opt] = xstrdup (p + opt_len);
+ }
+
+ else
+ gcc_unreachable ();
+ }
+
+ return ret;
+}
+
+/* Return a TARGET_OPTION_NODE tree of the target options listed or NULL. */
+
+tree
+ix86_valid_option_attribute_tree (tree args)
+{
+ const char *orig_arch_string = ix86_arch_string;
+ const char *orig_tune_string = ix86_tune_string;
+ const char *orig_fpmath_string = ix86_fpmath_string;
+ int orig_tune_defaulted = ix86_tune_defaulted;
+ int orig_arch_specified = ix86_arch_specified;
+ char *option_strings[IX86_FUNCTION_SPECIFIC_MAX] = { NULL, NULL, NULL };
+ tree t = NULL_TREE;
+ int i;
+ struct cl_target_option *def
+ = TREE_TARGET_OPTION (target_option_default_node);
+
+ /* Process each of the options on the chain. */
+ if (! ix86_valid_option_attribute_inner_p (args, option_strings))
+ return NULL_TREE;
+
+ /* If the changed options are different from the default, rerun override_options,
+ and then save the options away. The string options are are attribute options,
+ and will be undone when we copy the save structure. */
+ if (ix86_isa_flags != def->ix86_isa_flags
+ || target_flags != def->target_flags
+ || option_strings[IX86_FUNCTION_SPECIFIC_ARCH]
+ || option_strings[IX86_FUNCTION_SPECIFIC_TUNE]
+ || option_strings[IX86_FUNCTION_SPECIFIC_FPMATH])
+ {
+ /* If we are using the default tune= or arch=, undo the string assigned,
+ and use the default. */
+ if (option_strings[IX86_FUNCTION_SPECIFIC_ARCH])
+ ix86_arch_string = option_strings[IX86_FUNCTION_SPECIFIC_ARCH];
+ else if (!orig_arch_specified)
+ ix86_arch_string = NULL;
+
+ if (option_strings[IX86_FUNCTION_SPECIFIC_TUNE])
+ ix86_tune_string = option_strings[IX86_FUNCTION_SPECIFIC_TUNE];
+ else if (orig_tune_defaulted)
+ ix86_tune_string = NULL;
+
+ /* If fpmath= is not set, and we now have sse2 on 32-bit, use it. */
+ if (option_strings[IX86_FUNCTION_SPECIFIC_FPMATH])
+ ix86_fpmath_string = option_strings[IX86_FUNCTION_SPECIFIC_FPMATH];
+ else if (!TARGET_64BIT && TARGET_SSE)
+ ix86_fpmath_string = "sse,387";
+
+ /* Do any overrides, such as arch=xxx, or tune=xxx support. */
+ override_options (false);
+
+ /* Save the current options unless we are validating options for
+ #pragma. */
+ t = build_target_option_node ();
+
+ ix86_arch_string = orig_arch_string;
+ ix86_tune_string = orig_tune_string;
+ ix86_fpmath_string = orig_fpmath_string;
+
+ /* Free up memory allocated to hold the strings */
+ for (i = 0; i < IX86_FUNCTION_SPECIFIC_MAX; i++)
+ if (option_strings[i])
+ free (option_strings[i]);
+ }
+
+ return t;
+}
+
+/* Hook to validate attribute((option("string"))). */
+
+static bool
+ix86_valid_option_attribute_p (tree fndecl,
+ tree ARG_UNUSED (name),
+ tree args,
+ int ARG_UNUSED (flags))
+{
+ struct cl_target_option cur_opts;
+ bool ret = true;
+ tree new_opts;
+
+ cl_target_option_save (&cur_opts);
+ new_opts = ix86_valid_option_attribute_tree (args);
+ if (!new_opts)
+ ret = false;
+
+ else if (fndecl)
+ DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_opts;
+
+ cl_target_option_restore (&cur_opts);
+ return ret;
+}
+
+\f
+/* Hook to determine if one function can safely inline another. */
+
+static bool
+ix86_can_inline_p (tree caller, tree callee)
+{
+ bool ret = false;
+ tree caller_tree = DECL_FUNCTION_SPECIFIC_TARGET (caller);
+ tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET (callee);
+
+ /* If callee has no option attributes, then it is ok to inline. */
+ if (!callee_tree)
+ ret = true;
+
+ /* If caller has no option attributes, but callee does then it is not ok to
+ inline. */
+ else if (!caller_tree)
+ ret = false;
+
+ else
+ {
+ struct cl_target_option *caller_opts = TREE_TARGET_OPTION (caller_tree);
+ struct cl_target_option *callee_opts = TREE_TARGET_OPTION (callee_tree);
+
+ /* Callee's isa options should a subset of the caller's, i.e. a SSE5 function
+ can inline a SSE2 function but a SSE2 function can't inline a SSE5
+ function. */
+ if ((caller_opts->ix86_isa_flags & callee_opts->ix86_isa_flags)
+ != callee_opts->ix86_isa_flags)
+ ret = false;
+
+ /* See if we have the same non-isa options. */
+ else if (caller_opts->target_flags != callee_opts->target_flags)
+ ret = false;
+
+ /* See if arch, tune, etc. are the same. */
+ else if (caller_opts->arch != callee_opts->arch)
+ ret = false;
+
+ else if (caller_opts->tune != callee_opts->tune)
+ ret = false;
+
+ else if (caller_opts->fpmath != callee_opts->fpmath)
+ ret = false;
+
+ else if (caller_opts->branch_cost != callee_opts->branch_cost)
+ ret = false;
+
+ else
+ ret = true;
+ }
+
+ return ret;
+}
+
+\f
+/* Remember the last target of ix86_set_current_function. */
+static GTY(()) tree ix86_previous_fndecl;
+
+/* Establish appropriate back-end context for processing the function
+ FNDECL. The argument might be NULL to indicate processing at top
+ level, outside of any function scope. */
+static void
+ix86_set_current_function (tree fndecl)
+{
+ /* Only change the context if the function changes. This hook is called
+ several times in the course of compiling a function, and we don't want to
+ slow things down too much or call target_reinit when it isn't safe. */
+ if (fndecl && fndecl != ix86_previous_fndecl)
+ {
+ tree old_tree = (ix86_previous_fndecl
+ ? DECL_FUNCTION_SPECIFIC_TARGET (ix86_previous_fndecl)
+ : NULL_TREE);
+
+ tree new_tree = (fndecl
+ ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl)
+ : NULL_TREE);
+
+ ix86_previous_fndecl = fndecl;
+ if (old_tree == new_tree)
+ ;
+
+ else if (new_tree)
+ {
+ cl_target_option_restore (TREE_TARGET_OPTION (new_tree));
+ target_reinit ();
+ }
+
+ else if (old_tree)
+ {
+ struct cl_target_option *def
+ = TREE_TARGET_OPTION (target_option_current_node);
+
+ cl_target_option_restore (def);
+ target_reinit ();
+ }
+ }
+}
+
+\f
/* Return true if this goes in large data/bss. */
static bool
if (TARGET_64BIT)
{
/* Do not warn when emulating the MS ABI. */
- if (TREE_CODE (*node) != FUNCTION_TYPE || !ix86_function_type_abi (*node))
+ if (TREE_CODE (*node) != FUNCTION_TYPE || ix86_function_type_abi (*node)!=MS_ABI)
warning (OPT_Wattributes, "%qs attribute ignored",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
else
abi = lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (fntype)) ? SYSV_ABI : MS_ABI;
- if (DEFAULT_ABI == MS_ABI && abi == SYSV_ABI)
- sorry ("using sysv calling convention on target w64 is not supported");
-
return abi;
}
return DEFAULT_ABI;
contains_aligned_value_p (tree type)
{
enum machine_mode mode = TYPE_MODE (type);
- if (((TARGET_SSE && SSE_REG_MODE_P (mode)) || mode == TDmode)
+ if (((TARGET_SSE && SSE_REG_MODE_P (mode))
+ || mode == TDmode
+ || mode == TFmode
+ || mode == TCmode)
&& (!TYPE_USER_ALIGN (type) || TYPE_ALIGN (type) > 128))
return true;
if (TYPE_ALIGN (type) < 128)
align = GET_MODE_ALIGNMENT (mode);
if (align < PARM_BOUNDARY)
align = PARM_BOUNDARY;
- /* In 32bit, only _Decimal128 is aligned to its natural boundary. */
- if (!TARGET_64BIT && mode != TDmode)
+ /* In 32bit, only _Decimal128 and __float128 are aligned to their
+ natural boundaries. */
+ if (!TARGET_64BIT && mode != TDmode && mode != TFmode)
{
/* i386 ABI defines all arguments to be 4 byte aligned. We have to
make an exception for SSE modes since these require 128bit
to 8 byte boundaries. */
if (!type)
{
- if (!(TARGET_SSE && SSE_REG_MODE_P (mode)) && mode != TDmode)
+ if (!(TARGET_SSE && SSE_REG_MODE_P (mode)))
align = PARM_BOUNDARY;
}
else
if (mode == XFmode)
return 0;
- if (mode == TDmode)
- return 1;
-
if (size > 12)
return 1;
return 0;
\f
/* Create the va_list data type. */
+/* Returns the calling convention specific va_list date type.
+ The argument ABI can be DEFAULT_ABI, MS_ABI, or SYSV_ABI. */
+
static tree
-ix86_build_builtin_va_list (void)
+ix86_build_builtin_va_list_abi (enum calling_abi abi)
{
tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
/* For i386 we use plain pointer to argument area. */
- if (!TARGET_64BIT || ix86_cfun_abi () == MS_ABI)
+ if (!TARGET_64BIT || abi == MS_ABI)
return build_pointer_type (char_type_node);
record = (*lang_hooks.types.make_type) (RECORD_TYPE);
return build_array_type (record, build_index_type (size_zero_node));
}
+/* Setup the builtin va_list data type and for 64-bit the additional
+ calling convention specific va_list data types. */
+
+static tree
+ix86_build_builtin_va_list (void)
+{
+ tree ret = ix86_build_builtin_va_list_abi (DEFAULT_ABI);
+
+ /* Initialize abi specific va_list builtin types. */
+ if (TARGET_64BIT)
+ {
+ tree t;
+ if (DEFAULT_ABI == MS_ABI)
+ {
+ t = ix86_build_builtin_va_list_abi (SYSV_ABI);
+ if (TREE_CODE (t) != RECORD_TYPE)
+ t = build_variant_type_copy (t);
+ sysv_va_list_type_node = t;
+ }
+ else
+ {
+ t = ret;
+ if (TREE_CODE (t) != RECORD_TYPE)
+ t = build_variant_type_copy (t);
+ sysv_va_list_type_node = t;
+ }
+ if (DEFAULT_ABI != MS_ABI)
+ {
+ t = ix86_build_builtin_va_list_abi (MS_ABI);
+ if (TREE_CODE (t) != RECORD_TYPE)
+ t = build_variant_type_copy (t);
+ ms_va_list_type_node = t;
+ }
+ else
+ {
+ t = ret;
+ if (TREE_CODE (t) != RECORD_TYPE)
+ t = build_variant_type_copy (t);
+ ms_va_list_type_node = t;
+ }
+ }
+
+ return ret;
+}
+
/* Worker function for TARGET_SETUP_INCOMING_VARARGS. */
static void
label_ref = gen_rtx_LABEL_REF (Pmode, label);
/* Compute address to jump to :
- label - 5*eax + nnamed_sse_arguments*5 */
+ label - eax*4 + nnamed_sse_arguments*4 */
tmp_reg = gen_reg_rtx (Pmode);
nsse_reg = gen_reg_rtx (Pmode);
emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, AX_REG)));
setup_incoming_varargs_64 (&next_cum);
}
+/* Checks if TYPE is of kind va_list char *. */
+
+static bool
+is_va_list_char_pointer (tree type)
+{
+ tree canonic;
+
+ /* For 32-bit it is always true. */
+ if (!TARGET_64BIT)
+ return true;
+ canonic = ix86_canonical_va_list_type (type);
+ return (canonic == ms_va_list_type_node
+ || (DEFAULT_ABI == MS_ABI && canonic == va_list_type_node));
+}
+
/* Implement va_start. */
static void
tree type;
/* Only 64bit target needs something special. */
- if (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI)
+ if (!TARGET_64BIT || is_va_list_char_pointer (TREE_TYPE (valist)))
{
std_expand_builtin_va_start (valist, nextarg);
return;
}
- f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+ f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node));
f_fpr = TREE_CHAIN (f_gpr);
f_ovf = TREE_CHAIN (f_fpr);
f_sav = TREE_CHAIN (f_ovf);
int indirect_p = 0;
tree ptrtype;
enum machine_mode nat_mode;
+ int arg_boundary;
/* Only 64bit target needs something special. */
- if (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI)
+ if (!TARGET_64BIT || is_va_list_char_pointer (TREE_TYPE (valist)))
return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
- f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+ f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node));
f_fpr = TREE_CHAIN (f_gpr);
f_ovf = TREE_CHAIN (f_fpr);
f_sav = TREE_CHAIN (f_ovf);
/* ... otherwise out of the overflow area. */
+ /* When we align parameter on stack for caller, if the parameter
+ alignment is beyond PREFERRED_STACK_BOUNDARY, it will be
+ aligned at PREFERRED_STACK_BOUNDARY. We will match callee
+ here with caller. */
+ arg_boundary = FUNCTION_ARG_BOUNDARY (VOIDmode, type);
+ if ((unsigned int) arg_boundary > PREFERRED_STACK_BOUNDARY)
+ arg_boundary = PREFERRED_STACK_BOUNDARY;
+
/* Care for on-stack alignment if needed. */
- if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64
+ if (arg_boundary <= 64
|| integer_zerop (TYPE_SIZE (type)))
t = ovf;
else
{
- HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8;
+ HOST_WIDE_INT align = arg_boundary / 8;
t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovf), ovf,
size_int (align - 1));
t = fold_convert (sizetype, t);
xops[0] = gen_rtx_REG (Pmode, regno);
xops[1] = gen_rtx_MEM (Pmode, stack_pointer_rtx);
- if (TARGET_64BIT)
- output_asm_insn ("mov{q}\t{%1, %0|%0, %1}", xops);
- else
- output_asm_insn ("mov{l}\t{%1, %0|%0, %1}", xops);
+ output_asm_insn ("mov%z0\t{%1, %0|%0, %1}", xops);
output_asm_insn ("ret", xops);
}
xops[2] = gen_rtx_LABEL_REF (Pmode, label ? label : gen_label_rtx ());
if (!flag_pic)
- {
- if (TARGET_64BIT)
- output_asm_insn ("mov{q}\t{%2, %0|%0, %2}", xops);
- else
- output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops);
- }
+ output_asm_insn ("mov%z0\t{%2, %0|%0, %2}", xops);
else
output_asm_insn ("call\t%a2", xops);
CODE_LABEL_NUMBER (XEXP (xops[2], 0)));
if (flag_pic)
- {
- if (TARGET_64BIT)
- output_asm_insn ("pop{q}\t%0", xops);
- else
- output_asm_insn ("pop{l}\t%0", xops);
- }
+ output_asm_insn ("pop%z0\t%0", xops);
}
else
{
else
targetm.asm_out.internal_label (asm_out_file, "L",
CODE_LABEL_NUMBER (label));
-#endif
- }
-
- if (TARGET_MACHO)
- return "";
-
- if (!flag_pic || TARGET_DEEP_BRANCH_PREDICTION)
- {
- if (TARGET_64BIT)
- output_asm_insn ("add{q}\t{%1, %0|%0, %1}", xops);
- else
- output_asm_insn ("add{l}\t{%1, %0|%0, %1}", xops);
- }
- else
- {
- if (TARGET_64BIT)
- output_asm_insn ("add{q}\t{%1+[.-%a2], %0|%0, %1+(.-%a2)}", xops);
- else
- output_asm_insn ("add{l}\t{%1+[.-%a2], %0|%0, %1+(.-%a2)}", xops);
+#endif
}
+ if (TARGET_MACHO)
+ return "";
+
+ if (!flag_pic || TARGET_DEEP_BRANCH_PREDICTION)
+ output_asm_insn ("add%z0\t{%1, %0|%0, %1}", xops);
+ else
+ output_asm_insn ("add%z0\t{%1+[.-%a2], %0|%0, %1+(.-%a2)}", xops);
+
return "";
}
|| (TARGET_64BIT && frame->to_allocate >= (HOST_WIDE_INT) 0x80000000))
frame->save_regs_using_mov = false;
- if (TARGET_RED_ZONE && current_function_sp_is_unchanging
+ if (!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE && current_function_sp_is_unchanging
&& current_function_is_leaf
&& !ix86_current_function_calls_tls_descriptor)
{
avoid doing this if I am going to have to probe the stack since
at least on x86_64 the stack probe can turn into a call that clobbers
a red zone location */
- if (TARGET_RED_ZONE && frame.save_regs_using_mov
+ if (!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE && frame.save_regs_using_mov
&& (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT))
ix86_emit_save_regs_using_mov (frame_pointer_needed ? hard_frame_pointer_rtx
: stack_pointer_rtx,
}
if (frame.save_regs_using_mov
- && !(TARGET_RED_ZONE
+ && !(!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE
&& (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT)))
{
if (!frame_pointer_needed || !frame.to_allocate)
/* If not an i386, mov & pop is faster than "leave". */
else if (TARGET_USE_LEAVE || optimize_size
|| !cfun->machine->use_fast_prologue_epilogue)
- emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ());
+ emit_insn ((*ix86_gen_leave) ());
else
{
pro_epilogue_adjust_stack (stack_pointer_rtx,
hard_frame_pointer_rtx,
const0_rtx, style);
- if (TARGET_64BIT)
- emit_insn (gen_popdi1 (hard_frame_pointer_rtx));
- else
- emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
+
+ emit_insn ((*ix86_gen_pop1) (hard_frame_pointer_rtx));
}
}
else
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (ix86_save_reg (regno, false))
- {
- if (TARGET_64BIT)
- emit_insn (gen_popdi1 (gen_rtx_REG (Pmode, regno)));
- else
- emit_insn (gen_popsi1 (gen_rtx_REG (Pmode, regno)));
- }
+ emit_insn ((*ix86_gen_pop1) (gen_rtx_REG (Pmode, regno)));
if (frame_pointer_needed)
{
/* Leave results in shorter dependency chains on CPUs that are
able to grok it fast. */
if (TARGET_USE_LEAVE)
- emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ());
- else if (TARGET_64BIT)
- emit_insn (gen_popdi1 (hard_frame_pointer_rtx));
+ emit_insn ((*ix86_gen_leave) ());
else
- emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
+ emit_insn ((*ix86_gen_pop1) (hard_frame_pointer_rtx));
}
}
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
name = targetm.strip_name_encoding (name);
- prefix = name[0] == FASTCALL_PREFIX ? "*__imp_": "*__imp__";
+ prefix = name[0] == FASTCALL_PREFIX || user_label_prefix[0] == 0
+ ? "*__imp_" : "*__imp__";
namelen = strlen (name);
prefixlen = strlen (prefix);
imp_name = (char *) alloca (namelen + prefixlen + 1);
L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
C -- print opcode suffix for set/cmov insn.
c -- like C, but print reversed condition
+ E,e -- likewise, but for compare-and-branch fused insn.
F,f -- likewise, but for floating-point.
O -- if HAVE_AS_IX86_CMOV_SUN_SYNTAX, expand to "w.", "l." or "q.",
otherwise nothing
case 8:
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
{
+ if (MEM_P (x))
+ {
#ifdef GAS_MNEMONICS
- putc ('q', file);
+ putc ('q', file);
#else
- putc ('l', file);
- putc ('l', file);
+ putc ('l', file);
+ putc ('l', file);
#endif
+ }
+ else
+ putc ('q', file);
}
else
putc ('l', file);
if (CONST_INT_P (x) || ! SHIFT_DOUBLE_OMITS_COUNT)
{
PRINT_OPERAND (file, x, 0);
- putc (',', file);
+ fputs (", ", file);
}
return;
put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 1, file);
return;
+ case 'E':
+ put_condition_code (GET_CODE (x), CCmode, 0, 0, file);
+ return;
+
+ case 'e':
+ put_condition_code (GET_CODE (x), CCmode, 1, 0, file);
+ return;
+
case 'H':
/* It doesn't actually matter what mode we use here, as we're
only going to use this for printing. */
case TImode:
case TFmode:
- imode = TImode;
vec_mode = VOIDmode;
- gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
- lo = 0, hi = (HOST_WIDE_INT)1 << shift;
+ if (HOST_BITS_PER_WIDE_INT >= 64)
+ {
+ imode = TImode;
+ lo = 0, hi = (HOST_WIDE_INT)1 << shift;
+ }
+ else
+ {
+ rtvec vec;
+
+ imode = DImode;
+ lo = 0, hi = (HOST_WIDE_INT)1 << (shift - HOST_BITS_PER_WIDE_INT);
+
+ if (invert)
+ {
+ lo = ~lo, hi = ~hi;
+ v = constm1_rtx;
+ }
+ else
+ v = const0_rtx;
+
+ mask = immed_double_const (lo, hi, imode);
+
+ vec = gen_rtvec (2, v, mask);
+ v = gen_rtx_CONST_VECTOR (V2DImode, vec);
+ v = copy_to_mode_reg (mode, gen_lowpart (mode, v));
+
+ return v;
+ }
break;
default:
size = (GET_MODE_SIZE (mode) + 4) / 8;
gcc_assert (!REG_P (operand) || !MMX_REGNO_P (REGNO (operand)));
- gcc_assert (size >= 2 && size <= 3);
+ gcc_assert (size >= 2 && size <= 4);
/* Optimize constant pool reference to immediates. This is used by fp
moves, that force all constants to memory to allow combining. */
operand = copy_rtx (operand);
PUT_MODE (operand, Pmode);
- parts[0] = parts[1] = parts[2] = operand;
+ parts[0] = parts[1] = parts[2] = parts[3] = operand;
return size;
}
split_di (&operand, 1, &parts[0], &parts[1]);
else
{
+ int i;
+
if (REG_P (operand))
{
gcc_assert (reload_completed);
- parts[0] = gen_rtx_REG (SImode, REGNO (operand) + 0);
- parts[1] = gen_rtx_REG (SImode, REGNO (operand) + 1);
- if (size == 3)
- parts[2] = gen_rtx_REG (SImode, REGNO (operand) + 2);
+ for (i = 0; i < size; i++)
+ parts[i] = gen_rtx_REG (SImode, REGNO (operand) + i);
}
else if (offsettable_memref_p (operand))
{
operand = adjust_address (operand, SImode, 0);
parts[0] = operand;
- parts[1] = adjust_address (operand, SImode, 4);
- if (size == 3)
- parts[2] = adjust_address (operand, SImode, 8);
+ for (i = 1; i < size; i++)
+ parts[i] = adjust_address (operand, SImode, 4 * i);
}
else if (GET_CODE (operand) == CONST_DOUBLE)
{
REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
switch (mode)
{
+ case TFmode:
+ real_to_target (l, &r, mode);
+ parts[3] = gen_int_mode (l[3], SImode);
+ parts[2] = gen_int_mode (l[2], SImode);
+ break;
case XFmode:
REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
parts[2] = gen_int_mode (l[2], SImode);
return size;
}
-/* Emit insns to perform a move or push of DI, DF, and XF values.
+/* Emit insns to perform a move or push of DI, DF, XF, and TF values.
Return false when normal moves are needed; true when all required
insns have been emitted. Operands 2-4 contain the input values
int the correct order; operands 5-7 contain the output values. */
void
ix86_split_long_move (rtx operands[])
{
- rtx part[2][3];
- int nparts;
+ rtx part[2][4];
+ int nparts, i, j;
int push = 0;
int collisions = 0;
enum machine_mode mode = GET_MODE (operands[0]);
+ bool collisionparts[4];
/* The DFmode expanders may ask us to move double.
For 64bit target this is single move. By hiding the fact
/* When emitting push, take care for source operands on the stack. */
if (push && MEM_P (operands[1])
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
- {
- if (nparts == 3)
- part[1][1] = change_address (part[1][1], GET_MODE (part[1][1]),
- XEXP (part[1][2], 0));
- part[1][0] = change_address (part[1][0], GET_MODE (part[1][0]),
- XEXP (part[1][1], 0));
- }
+ for (i = 0; i < nparts - 1; i++)
+ part[1][i] = change_address (part[1][i],
+ GET_MODE (part[1][i]),
+ XEXP (part[1][i + 1], 0));
/* We need to do copy in the right order in case an address register
of the source overlaps the destination. */
if (REG_P (part[0][0]) && MEM_P (part[1][0]))
{
- if (reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0)))
- collisions++;
- if (reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
- collisions++;
- if (nparts == 3
- && reg_overlap_mentioned_p (part[0][2], XEXP (part[1][0], 0)))
- collisions++;
+ rtx tmp;
+
+ for (i = 0; i < nparts; i++)
+ {
+ collisionparts[i]
+ = reg_overlap_mentioned_p (part[0][i], XEXP (part[1][0], 0));
+ if (collisionparts[i])
+ collisions++;
+ }
/* Collision in the middle part can be handled by reordering. */
- if (collisions == 1 && nparts == 3
- && reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
+ if (collisions == 1 && nparts == 3 && collisionparts [1])
{
- rtx tmp;
tmp = part[0][1]; part[0][1] = part[0][2]; part[0][2] = tmp;
tmp = part[1][1]; part[1][1] = part[1][2]; part[1][2] = tmp;
}
+ else if (collisions == 1
+ && nparts == 4
+ && (collisionparts [1] || collisionparts [2]))
+ {
+ if (collisionparts [1])
+ {
+ tmp = part[0][1]; part[0][1] = part[0][2]; part[0][2] = tmp;
+ tmp = part[1][1]; part[1][1] = part[1][2]; part[1][2] = tmp;
+ }
+ else
+ {
+ tmp = part[0][2]; part[0][2] = part[0][3]; part[0][3] = tmp;
+ tmp = part[1][2]; part[1][2] = part[1][3]; part[1][3] = tmp;
+ }
+ }
/* If there are more collisions, we can't handle it by reordering.
Do an lea to the last part and use only one colliding move. */
emit_insn (gen_rtx_SET (VOIDmode, base, XEXP (part[1][0], 0)));
part[1][0] = replace_equiv_address (part[1][0], base);
- part[1][1] = replace_equiv_address (part[1][1],
- plus_constant (base, UNITS_PER_WORD));
- if (nparts == 3)
- part[1][2] = replace_equiv_address (part[1][2],
- plus_constant (base, 8));
+ for (i = 1; i < nparts; i++)
+ {
+ tmp = plus_constant (base, UNITS_PER_WORD * i);
+ part[1][i] = replace_equiv_address (part[1][i], tmp);
+ }
}
}
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-4)));
emit_move_insn (part[0][2], part[1][2]);
}
+ else if (nparts == 4)
+ {
+ emit_move_insn (part[0][3], part[1][3]);
+ emit_move_insn (part[0][2], part[1][2]);
+ }
}
else
{
&& REG_P (part[1][1])
&& (REGNO (part[0][0]) == REGNO (part[1][1])
|| (nparts == 3
- && REGNO (part[0][0]) == REGNO (part[1][2]))))
+ && REGNO (part[0][0]) == REGNO (part[1][2]))
+ || (nparts == 4
+ && REGNO (part[0][0]) == REGNO (part[1][3]))))
|| (collisions > 0
&& reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0))))
{
- if (nparts == 3)
- {
- operands[2] = part[0][2];
- operands[3] = part[0][1];
- operands[4] = part[0][0];
- operands[5] = part[1][2];
- operands[6] = part[1][1];
- operands[7] = part[1][0];
- }
- else
+ for (i = 0, j = nparts - 1; i < nparts; i++, j--)
{
- operands[2] = part[0][1];
- operands[3] = part[0][0];
- operands[5] = part[1][1];
- operands[6] = part[1][0];
+ operands[2 + i] = part[0][j];
+ operands[6 + i] = part[1][j];
}
}
else
{
- if (nparts == 3)
- {
- operands[2] = part[0][0];
- operands[3] = part[0][1];
- operands[4] = part[0][2];
- operands[5] = part[1][0];
- operands[6] = part[1][1];
- operands[7] = part[1][2];
- }
- else
+ for (i = 0; i < nparts; i++)
{
- operands[2] = part[0][0];
- operands[3] = part[0][1];
- operands[5] = part[1][0];
- operands[6] = part[1][1];
+ operands[2 + i] = part[0][i];
+ operands[6 + i] = part[1][i];
}
}
/* If optimizing for size, attempt to locally unCSE nonzero constants. */
if (optimize_size)
{
- if (CONST_INT_P (operands[5])
- && operands[5] != const0_rtx
- && REG_P (operands[2]))
- {
- if (CONST_INT_P (operands[6])
- && INTVAL (operands[6]) == INTVAL (operands[5]))
- operands[6] = operands[2];
-
- if (nparts == 3
- && CONST_INT_P (operands[7])
- && INTVAL (operands[7]) == INTVAL (operands[5]))
- operands[7] = operands[2];
- }
-
- if (nparts == 3
- && CONST_INT_P (operands[6])
- && operands[6] != const0_rtx
- && REG_P (operands[3])
- && CONST_INT_P (operands[7])
- && INTVAL (operands[7]) == INTVAL (operands[6]))
- operands[7] = operands[3];
+ for (j = 0; j < nparts - 1; j++)
+ if (CONST_INT_P (operands[6 + j])
+ && operands[6 + j] != const0_rtx
+ && REG_P (operands[2 + j]))
+ for (i = j; i < nparts - 1; i++)
+ if (CONST_INT_P (operands[7 + i])
+ && INTVAL (operands[7 + i]) == INTVAL (operands[6 + j]))
+ operands[7 + i] = operands[2 + j];
}
- emit_move_insn (operands[2], operands[5]);
- emit_move_insn (operands[3], operands[6]);
- if (nparts == 3)
- emit_move_insn (operands[4], operands[7]);
+ for (i = 0; i < nparts; i++)
+ emit_move_insn (operands[2 + i], operands[6 + i]);
return;
}
if (!rtx_equal_p (operands[0], operands[1]))
emit_move_insn (operands[0], operands[1]);
emit_insn ((mode == DImode
- ? gen_x86_shld_1
+ ? gen_x86_shld
: gen_x86_64_shld) (high[0], low[0], GEN_INT (count)));
ix86_expand_ashl_const (low[0], count, mode);
}
(mode == DImode ? split_di : split_ti) (operands, 1, low, high);
emit_insn ((mode == DImode
- ? gen_x86_shld_1
+ ? gen_x86_shld
: gen_x86_64_shld) (high[0], low[0], operands[2]));
}
ix86_expand_clear (scratch);
emit_insn ((mode == DImode
? gen_x86_shift_adj_1
- : gen_x86_64_shift_adj) (high[0], low[0], operands[2], scratch));
+ : gen_x86_64_shift_adj_1) (high[0], low[0], operands[2],
+ scratch));
}
else
- emit_insn (gen_x86_shift_adj_2 (high[0], low[0], operands[2]));
+ emit_insn ((mode == DImode
+ ? gen_x86_shift_adj_2
+ : gen_x86_64_shift_adj_2) (high[0], low[0], operands[2]));
}
void
if (!rtx_equal_p (operands[0], operands[1]))
emit_move_insn (operands[0], operands[1]);
emit_insn ((mode == DImode
- ? gen_x86_shrd_1
+ ? gen_x86_shrd
: gen_x86_64_shrd) (low[0], high[0], GEN_INT (count)));
emit_insn ((mode == DImode
? gen_ashrsi3
(mode == DImode ? split_di : split_ti) (operands, 1, low, high);
emit_insn ((mode == DImode
- ? gen_x86_shrd_1
+ ? gen_x86_shrd
: gen_x86_64_shrd) (low[0], high[0], operands[2]));
emit_insn ((mode == DImode
? gen_ashrsi3
GEN_INT (single_width - 1)));
emit_insn ((mode == DImode
? gen_x86_shift_adj_1
- : gen_x86_64_shift_adj) (low[0], high[0], operands[2],
- scratch));
+ : gen_x86_64_shift_adj_1) (low[0], high[0], operands[2],
+ scratch));
}
else
- emit_insn (gen_x86_shift_adj_3 (low[0], high[0], operands[2]));
+ emit_insn ((mode == DImode
+ ? gen_x86_shift_adj_3
+ : gen_x86_64_shift_adj_3) (low[0], high[0], operands[2]));
}
}
if (!rtx_equal_p (operands[0], operands[1]))
emit_move_insn (operands[0], operands[1]);
emit_insn ((mode == DImode
- ? gen_x86_shrd_1
+ ? gen_x86_shrd
: gen_x86_64_shrd) (low[0], high[0], GEN_INT (count)));
emit_insn ((mode == DImode
? gen_lshrsi3
(mode == DImode ? split_di : split_ti) (operands, 1, low, high);
emit_insn ((mode == DImode
- ? gen_x86_shrd_1
+ ? gen_x86_shrd
: gen_x86_64_shrd) (low[0], high[0], operands[2]));
emit_insn ((mode == DImode
? gen_lshrsi3
ix86_expand_clear (scratch);
emit_insn ((mode == DImode
? gen_x86_shift_adj_1
- : gen_x86_64_shift_adj) (low[0], high[0], operands[2],
- scratch));
+ : gen_x86_64_shift_adj_1) (low[0], high[0], operands[2],
+ scratch));
}
else
- emit_insn (gen_x86_shift_adj_2 (low[0], high[0], operands[2]));
+ emit_insn ((mode == DImode
+ ? gen_x86_shift_adj_2
+ : gen_x86_64_shift_adj_2) (low[0], high[0], operands[2]));
}
}
QImode, 1, end_0_label);
/* Increment the address. */
- if (TARGET_64BIT)
- emit_insn (gen_adddi3 (out, out, const1_rtx));
- else
- emit_insn (gen_addsi3 (out, out, const1_rtx));
+ emit_insn ((*ix86_gen_add3) (out, out, const1_rtx));
/* Not needed with an alignment of 2 */
if (align != 2)
emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL, QImode, 1,
end_0_label);
- if (TARGET_64BIT)
- emit_insn (gen_adddi3 (out, out, const1_rtx));
- else
- emit_insn (gen_addsi3 (out, out, const1_rtx));
+ emit_insn ((*ix86_gen_add3) (out, out, const1_rtx));
emit_label (align_3_label);
}
emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL, QImode, 1,
end_0_label);
- if (TARGET_64BIT)
- emit_insn (gen_adddi3 (out, out, const1_rtx));
- else
- emit_insn (gen_addsi3 (out, out, const1_rtx));
+ emit_insn ((*ix86_gen_add3) (out, out, const1_rtx));
}
/* Generate loop to check 4 bytes at a time. It is not a good idea to
mem = change_address (src, SImode, out);
emit_move_insn (scratch, mem);
- if (TARGET_64BIT)
- emit_insn (gen_adddi3 (out, out, GEN_INT (4)));
- else
- emit_insn (gen_addsi3 (out, out, GEN_INT (4)));
+ emit_insn ((*ix86_gen_add3) (out, out, GEN_INT (4)));
/* This formula yields a nonzero result iff one of the bytes is zero.
This saves three branches inside loop and many cycles. */
/* Not in the first two. Move two bytes forward. */
emit_insn (gen_lshrsi3 (tmpreg, tmpreg, GEN_INT (16)));
- if (TARGET_64BIT)
- emit_insn (gen_adddi3 (out, out, const2_rtx));
- else
- emit_insn (gen_addsi3 (out, out, const2_rtx));
+ emit_insn ((*ix86_gen_add3) (out, out, const2_rtx));
emit_label (end_2_label);
tmpreg = gen_lowpart (QImode, tmpreg);
emit_insn (gen_addqi3_cc (tmpreg, tmpreg, tmpreg));
cmp = gen_rtx_LTU (Pmode, gen_rtx_REG (CCmode, FLAGS_REG), const0_rtx);
- if (TARGET_64BIT)
- emit_insn (gen_subdi3_carry_rex64 (out, out, GEN_INT (3), cmp));
- else
- emit_insn (gen_subsi3_carry (out, out, GEN_INT (3), cmp));
+ emit_insn ((*ix86_gen_sub3_carry) (out, out, GEN_INT (3), cmp));
emit_label (end_0_label);
}
/* strlensi_unroll_1 returns the address of the zero at the end of
the string, like memchr(), so compute the length by subtracting
the start address. */
- if (TARGET_64BIT)
- emit_insn (gen_subdi3 (out, out, addr));
- else
- emit_insn (gen_subsi3 (out, out, addr));
+ emit_insn ((*ix86_gen_sub3) (out, out, addr));
}
else
{
unspec = gen_rtx_UNSPEC (Pmode, gen_rtvec (4, src, eoschar, align,
scratch4), UNSPEC_SCAS);
emit_insn (gen_strlenqi_1 (scratch1, scratch3, unspec));
- if (TARGET_64BIT)
- {
- emit_insn (gen_one_cmpldi2 (scratch2, scratch1));
- emit_insn (gen_adddi3 (out, scratch2, constm1_rtx));
- }
- else
- {
- emit_insn (gen_one_cmplsi2 (scratch2, scratch1));
- emit_insn (gen_addsi3 (out, scratch2, constm1_rtx));
- }
+ emit_insn ((*ix86_gen_one_cmpl2) (scratch2, scratch1));
+ emit_insn ((*ix86_gen_add3) (out, scratch2, constm1_rtx));
}
return 1;
}
if (TYPE_MODE (type) == DCmode && align < 64)
return 64;
- if (TYPE_MODE (type) == XCmode && align < 128)
+ if ((TYPE_MODE (type) == XCmode
+ || TYPE_MODE (type) == TCmode) && align < 128)
return 128;
}
else if ((TREE_CODE (type) == RECORD_TYPE
{
if (TYPE_MODE (type) == DCmode && align < 64)
return 64;
- if (TYPE_MODE (type) == XCmode && align < 128)
+ if ((TYPE_MODE (type) == XCmode
+ || TYPE_MODE (type) == TCmode) && align < 128)
return 128;
}
else if ((TREE_CODE (type) == RECORD_TYPE
/* Table for the ix86 builtin decls. */
static GTY(()) tree ix86_builtins[(int) IX86_BUILTIN_MAX];
-/* Add an ix86 target builtin function with CODE, NAME and TYPE. Do so,
- * if the target_flags include one of MASK. Stores the function decl
- * in the ix86_builtins array.
- * Returns the function decl or NULL_TREE, if the builtin was not added. */
+/* Table to record which ISA options the builtin needs. */
+static int ix86_builtins_isa[(int) IX86_BUILTIN_MAX];
+
+/* Add an ix86 target builtin function with CODE, NAME and TYPE. Save the MASK
+ * of which isa_flags to use in the ix86_builtins_isa array. Stores the
+ * function decl in the ix86_builtins array. Returns the function decl or
+ * NULL_TREE, if the builtin was not added.
+ *
+ * Record all builtins, even if it isn't an instruction set in the current ISA
+ * in case the user uses function specific options for a different ISA. When
+ * the builtin is expanded, check at that time whether it is valid. */
static inline tree
def_builtin (int mask, const char *name, tree type, enum ix86_builtins code)
{
tree decl = NULL_TREE;
- if (mask & ix86_isa_flags
- && (!(mask & OPTION_MASK_ISA_64BIT) || TARGET_64BIT))
+ if (!(mask & OPTION_MASK_ISA_64BIT) || TARGET_64BIT)
{
decl = add_builtin_function (name, type, code, BUILT_IN_MD,
NULL, NULL_TREE);
ix86_builtins[(int) code] = decl;
+ ix86_builtins_isa[(int) code] = mask;
}
return decl;
{ OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_vmsqrtv2df2, "__builtin_ia32_sqrtsd", IX86_BUILTIN_SQRTSD, UNKNOWN, (int) V2DF_FTYPE_V2DF_VEC_MERGE },
+ { OPTION_MASK_ISA_SSE2, CODE_FOR_abstf2, 0, IX86_BUILTIN_FABSQ, UNKNOWN, (int) FLOAT128_FTYPE_FLOAT128 },
+ { OPTION_MASK_ISA_SSE2, CODE_FOR_copysigntf3, 0, IX86_BUILTIN_COPYSIGNQ, UNKNOWN, (int) FLOAT128_FTYPE_FLOAT128_FLOAT128 },
+
/* SSE2 MMX */
{ OPTION_MASK_ISA_SSE2, CODE_FOR_mmx_addv1di3, "__builtin_ia32_paddq", IX86_BUILTIN_PADDQ, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI },
{ OPTION_MASK_ISA_SSE2, CODE_FOR_mmx_subv1di3, "__builtin_ia32_psubq", IX86_BUILTIN_PSUBQ, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI },
/* PCLMUL */
{ OPTION_MASK_ISA_SSE2, CODE_FOR_pclmulqdq, 0, IX86_BUILTIN_PCLMULQDQ128, UNKNOWN, (int) V2DI_FTYPE_V2DI_V2DI_INT },
-
- /* 64bit */
- { OPTION_MASK_ISA_64BIT, CODE_FOR_abstf2, 0, IX86_BUILTIN_FABSQ, UNKNOWN, (int) FLOAT128_FTYPE_FLOAT128 },
- { OPTION_MASK_ISA_64BIT, CODE_FOR_copysigntf3, 0, IX86_BUILTIN_COPYSIGNQ, UNKNOWN, (int) FLOAT128_FTYPE_FLOAT128_FLOAT128 },
};
/* SSE5 */
{ OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv2di3, "__builtin_ia32_pcomtrueuq", IX86_BUILTIN_PCOMTRUEUQ, PCOM_TRUE, (int)MULTI_ARG_2_DI_TF },
};
-/* Set up all the MMX/SSE builtins. This is not called if TARGET_MMX
- is zero. Otherwise, if TARGET_SSE is not set, only expand the MMX
- builtins. */
+/* Set up all the MMX/SSE builtins, even builtins for instructions that are not
+ in the current target ISA to allow the user to compile particular modules
+ with different target specific options that differ from the command line
+ options. */
static void
ix86_init_mmx_sse_builtins (void)
{
tree ftype;
- /* The __float80 type. */
- if (TYPE_MODE (long_double_type_node) == XFmode)
- (*lang_hooks.types.register_builtin_type) (long_double_type_node,
- "__float80");
- else
- {
- /* The __float80 type. */
- tree float80_type_node = make_node (REAL_TYPE);
-
- TYPE_PRECISION (float80_type_node) = 80;
- layout_type (float80_type_node);
- (*lang_hooks.types.register_builtin_type) (float80_type_node,
- "__float80");
- }
-
- if (TARGET_64BIT)
- {
- tree float128_type_node = make_node (REAL_TYPE);
-
- TYPE_PRECISION (float128_type_node) = 128;
- layout_type (float128_type_node);
- (*lang_hooks.types.register_builtin_type) (float128_type_node,
- "__float128");
-
- /* TFmode support builtins. */
- ftype = build_function_type (float128_type_node,
- void_list_node);
- def_builtin (OPTION_MASK_ISA_64BIT, "__builtin_infq", ftype, IX86_BUILTIN_INFQ);
-
- ftype = build_function_type_list (float128_type_node,
- float128_type_node,
- NULL_TREE);
- def_builtin_const (OPTION_MASK_ISA_64BIT, "__builtin_fabsq", ftype, IX86_BUILTIN_FABSQ);
-
- ftype = build_function_type_list (float128_type_node,
- float128_type_node,
- float128_type_node,
- NULL_TREE);
- def_builtin_const (OPTION_MASK_ISA_64BIT, "__builtin_copysignq", ftype, IX86_BUILTIN_COPYSIGNQ);
- }
-
/* Add all special builtins with variable number of operands. */
for (i = 0, d = bdesc_special_args;
i < ARRAY_SIZE (bdesc_special_args);
def_builtin (OPTION_MASK_ISA_SSE3, "__builtin_ia32_mwait", void_ftype_unsigned_unsigned, IX86_BUILTIN_MWAIT);
/* AES */
- if (TARGET_AES)
- {
- /* Define AES built-in functions only if AES is enabled. */
- def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesenc128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESENC128);
- def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesenclast128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESENCLAST128);
- def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesdec128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESDEC128);
- def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesdeclast128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESDECLAST128);
- def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesimc128", v2di_ftype_v2di, IX86_BUILTIN_AESIMC128);
- def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aeskeygenassist128", v2di_ftype_v2di_int, IX86_BUILTIN_AESKEYGENASSIST128);
- }
+ def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesenc128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESENC128);
+ def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesenclast128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESENCLAST128);
+ def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesdec128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESDEC128);
+ def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesdeclast128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESDECLAST128);
+ def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesimc128", v2di_ftype_v2di, IX86_BUILTIN_AESIMC128);
+ def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aeskeygenassist128", v2di_ftype_v2di_int, IX86_BUILTIN_AESKEYGENASSIST128);
/* PCLMUL */
- if (TARGET_PCLMUL)
- {
- /* Define PCLMUL built-in function only if PCLMUL is enabled. */
- def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_pclmulqdq128", v2di_ftype_v2di_v2di_int, IX86_BUILTIN_PCLMULQDQ128);
- }
+ def_builtin_const (OPTION_MASK_ISA_PCLMUL, "__builtin_ia32_pclmulqdq128", v2di_ftype_v2di_v2di_int, IX86_BUILTIN_PCLMULQDQ128);
/* Access to the vec_init patterns. */
ftype = build_function_type_list (V2SI_type_node, integer_type_node,
}
}
+/* Internal method for ix86_init_builtins. */
+
+static void
+ix86_init_builtins_va_builtins_abi (void)
+{
+ tree ms_va_ref, sysv_va_ref;
+ tree fnvoid_va_end_ms, fnvoid_va_end_sysv;
+ tree fnvoid_va_start_ms, fnvoid_va_start_sysv;
+ tree fnvoid_va_copy_ms, fnvoid_va_copy_sysv;
+ tree fnattr_ms = NULL_TREE, fnattr_sysv = NULL_TREE;
+
+ if (!TARGET_64BIT)
+ return;
+ fnattr_ms = build_tree_list (get_identifier ("ms_abi"), NULL_TREE);
+ fnattr_sysv = build_tree_list (get_identifier ("sysv_abi"), NULL_TREE);
+ ms_va_ref = build_reference_type (ms_va_list_type_node);
+ sysv_va_ref =
+ build_pointer_type (TREE_TYPE (sysv_va_list_type_node));
+
+ fnvoid_va_end_ms =
+ build_function_type_list (void_type_node, ms_va_ref, NULL_TREE);
+ fnvoid_va_start_ms =
+ build_varargs_function_type_list (void_type_node, ms_va_ref, NULL_TREE);
+ fnvoid_va_end_sysv =
+ build_function_type_list (void_type_node, sysv_va_ref, NULL_TREE);
+ fnvoid_va_start_sysv =
+ build_varargs_function_type_list (void_type_node, sysv_va_ref,
+ NULL_TREE);
+ fnvoid_va_copy_ms =
+ build_function_type_list (void_type_node, ms_va_ref, ms_va_list_type_node,
+ NULL_TREE);
+ fnvoid_va_copy_sysv =
+ build_function_type_list (void_type_node, sysv_va_ref,
+ sysv_va_ref, NULL_TREE);
+
+ add_builtin_function ("__builtin_ms_va_start", fnvoid_va_start_ms,
+ BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_ms);
+ add_builtin_function ("__builtin_ms_va_end", fnvoid_va_end_ms,
+ BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_ms);
+ add_builtin_function ("__builtin_ms_va_copy", fnvoid_va_copy_ms,
+ BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_ms);
+ add_builtin_function ("__builtin_sysv_va_start", fnvoid_va_start_sysv,
+ BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_sysv);
+ add_builtin_function ("__builtin_sysv_va_end", fnvoid_va_end_sysv,
+ BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_sysv);
+ add_builtin_function ("__builtin_sysv_va_copy", fnvoid_va_copy_sysv,
+ BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_sysv);
+}
+
static void
ix86_init_builtins (void)
{
- if (TARGET_MMX)
- ix86_init_mmx_sse_builtins ();
+ tree float128_type_node = make_node (REAL_TYPE);
+ tree ftype, decl;
+
+ /* The __float80 type. */
+ if (TYPE_MODE (long_double_type_node) == XFmode)
+ (*lang_hooks.types.register_builtin_type) (long_double_type_node,
+ "__float80");
+ else
+ {
+ /* The __float80 type. */
+ tree float80_type_node = make_node (REAL_TYPE);
+
+ TYPE_PRECISION (float80_type_node) = 80;
+ layout_type (float80_type_node);
+ (*lang_hooks.types.register_builtin_type) (float80_type_node,
+ "__float80");
+ }
+
+ /* The __float128 type. */
+ TYPE_PRECISION (float128_type_node) = 128;
+ layout_type (float128_type_node);
+ (*lang_hooks.types.register_builtin_type) (float128_type_node,
+ "__float128");
+
+ /* TFmode support builtins. */
+ ftype = build_function_type (float128_type_node, void_list_node);
+ decl = add_builtin_function ("__builtin_infq", ftype,
+ IX86_BUILTIN_INFQ, BUILT_IN_MD,
+ NULL, NULL_TREE);
+ ix86_builtins[(int) IX86_BUILTIN_INFQ] = decl;
+
+ /* We will expand them to normal call if SSE2 isn't available since
+ they are used by libgcc. */
+ ftype = build_function_type_list (float128_type_node,
+ float128_type_node,
+ NULL_TREE);
+ decl = add_builtin_function ("__builtin_fabsq", ftype,
+ IX86_BUILTIN_FABSQ, BUILT_IN_MD,
+ "__fabstf2", NULL_TREE);
+ ix86_builtins[(int) IX86_BUILTIN_FABSQ] = decl;
+ TREE_READONLY (decl) = 1;
+
+ ftype = build_function_type_list (float128_type_node,
+ float128_type_node,
+ float128_type_node,
+ NULL_TREE);
+ decl = add_builtin_function ("__builtin_copysignq", ftype,
+ IX86_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
+ "__copysigntf3", NULL_TREE);
+ ix86_builtins[(int) IX86_BUILTIN_COPYSIGNQ] = decl;
+ TREE_READONLY (decl) = 1;
+
+ ix86_init_mmx_sse_builtins ();
+ if (TARGET_64BIT)
+ ix86_init_builtins_va_builtins_abi ();
}
/* Errors in the source file can cause expand_expr to return const0_rtx
enum machine_mode mode0, mode1, mode2;
unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+ /* Determine whether the builtin function is available under the current ISA.
+ Originally the builtin was not created if it wasn't applicable to the
+ current ISA based on the command line switches. With function specific
+ options, we need to check in the context of the function making the call
+ whether it is supported. */
+ if (ix86_builtins_isa[fcode]
+ && !(ix86_builtins_isa[fcode] & ix86_isa_flags))
+ {
+ char *opts = ix86_target_string (ix86_builtins_isa[fcode], 0, NULL,
+ NULL, NULL, false);
+
+ if (!opts)
+ error ("%qE needs unknown isa option", fndecl);
+ else
+ {
+ gcc_assert (opts != NULL);
+ error ("%qE needs isa option %s", fndecl, opts);
+ free (opts);
+ }
+ return const0_rtx;
+ }
+
switch (fcode)
{
case IX86_BUILTIN_MASKMOVQ:
op1 = copy_to_mode_reg (SImode, op1);
if (!REG_P (op2))
op2 = copy_to_mode_reg (SImode, op2);
- if (!TARGET_64BIT)
- emit_insn (gen_sse3_monitor (op0, op1, op2));
- else
- emit_insn (gen_sse3_monitor64 (op0, op1, op2));
+ emit_insn ((*ix86_gen_monitor) (op0, op1, op2));
return 0;
case IX86_BUILTIN_MWAIT:
i < ARRAY_SIZE (bdesc_args);
i++, d++)
if (d->code == fcode)
- return ix86_expand_args_builtin (d, exp, target);
+ switch (fcode)
+ {
+ case IX86_BUILTIN_FABSQ:
+ case IX86_BUILTIN_COPYSIGNQ:
+ if (!TARGET_SSE2)
+ /* Emit a normal call if SSE2 isn't available. */
+ return expand_call (exp, target, ignore);
+ default:
+ return ix86_expand_args_builtin (d, exp, target);
+ }
for (i = 0, d = bdesc_comi; i < ARRAY_SIZE (bdesc_comi); i++, d++)
if (d->code == fcode)
rtx result;
gcc_assert (reload_completed);
- if (TARGET_RED_ZONE)
+ if (!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE)
{
result = gen_rtx_MEM (mode,
gen_rtx_PLUS (Pmode,
GEN_INT (-RED_ZONE_SIZE)));
emit_move_insn (result, operand);
}
- else if (!TARGET_RED_ZONE && TARGET_64BIT)
+ else if ((TARGET_64BIT_MS_ABI || !TARGET_RED_ZONE) && TARGET_64BIT)
{
switch (mode)
{
void
ix86_free_from_memory (enum machine_mode mode)
{
- if (!TARGET_RED_ZONE)
+ if (!TARGET_RED_ZONE || TARGET_64BIT_MS_ABI)
{
int size;
symb = (*targetm.strip_name_encoding) (symb);
length = strlen (stub);
- binder_name = alloca (length + 32);
+ binder_name = XALLOCAVEC (char, length + 32);
GEN_BINDER_NAME_FOR_STUB (binder_name, stub, length);
length = strlen (symb);
- symbol_name = alloca (length + 32);
+ symbol_name = XALLOCAVEC (char, length + 32);
GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length);
sprintf (lazy_ptr_name, "L%d$lz", label);
reg_alloc_order [pos++] = 0;
}
+/* Handle a "ms_abi" or "sysv" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+ix86_handle_abi_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_TYPE
+ && TREE_CODE (*node) != METHOD_TYPE
+ && TREE_CODE (*node) != FIELD_DECL
+ && TREE_CODE (*node) != TYPE_DECL)
+ {
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ if (!TARGET_64BIT)
+ {
+ warning (OPT_Wattributes, "%qs attribute only available for 64-bit",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ /* Can combine regparm with all attributes but fastcall. */
+ if (is_attribute_p ("ms_abi", name))
+ {
+ if (lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (*node)))
+ {
+ error ("ms_abi and sysv_abi attributes are not compatible");
+ }
+
+ return NULL_TREE;
+ }
+ else if (is_attribute_p ("sysv_abi", name))
+ {
+ if (lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (*node)))
+ {
+ error ("ms_abi and sysv_abi attributes are not compatible");
+ }
+
+ return NULL_TREE;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in
struct attribute_spec.handler. */
static tree
/* Put the this parameter into %eax. */
xops[0] = this_param;
xops[1] = this_reg = gen_rtx_REG (Pmode, AX_REG);
- if (TARGET_64BIT)
- output_asm_insn ("mov{q}\t{%0, %1|%1, %0}", xops);
- else
- output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops);
+ output_asm_insn ("mov%z1\t{%0, %1|%1, %0}", xops);
}
else
this_reg = NULL_RTX;
xops[0] = gen_rtx_MEM (Pmode, this_reg);
xops[1] = tmp;
- if (TARGET_64BIT)
- output_asm_insn ("mov{q}\t{%0, %1|%1, %0}", xops);
- else
- output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops);
+ output_asm_insn ("mov%z1\t{%0, %1|%1, %0}", xops);
/* Adjust the this parameter. */
xops[0] = gen_rtx_MEM (Pmode, plus_constant (tmp, vcall_offset));
xops[0] = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, tmp, tmp2));
}
xops[1] = this_reg;
- if (TARGET_64BIT)
- output_asm_insn ("add{q}\t{%0, %1|%1, %0}", xops);
- else
- output_asm_insn ("add{l}\t{%0, %1|%1, %0}", xops);
+ output_asm_insn ("add%z1\t{%0, %1|%1, %0}", xops);
}
/* If necessary, drop THIS back to its stack slot. */
{
xops[0] = this_reg;
xops[1] = this_param;
- if (TARGET_64BIT)
- output_asm_insn ("mov{q}\t{%0, %1|%1, %0}", xops);
- else
- output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops);
+ output_asm_insn ("mov%z1\t{%0, %1|%1, %0}", xops);
}
xops[0] = XEXP (DECL_RTL (function), 0);
if (DECIMAL_FLOAT_MODE_P (mode))
return true;
else if (mode == TFmode)
- return TARGET_64BIT;
+ return true;
else
return default_scalar_mode_supported_p (mode);
}
static enum machine_mode
ix86_c_mode_for_suffix (char suffix)
{
- if (TARGET_64BIT && suffix == 'q')
+ if (suffix == 'q')
return TFmode;
- if (TARGET_MMX && suffix == 'w')
+ if (suffix == 'w')
return XFmode;
return VOIDmode;
OPERANDS is the array of operands.
NUM is the number of operands.
USES_OC0 is true if the instruction uses OC0 and provides 4 variants.
- NUM_MEMORY is the maximum number of memory operands to accept. */
+ NUM_MEMORY is the maximum number of memory operands to accept.
+ when COMMUTATIVE is set, operand 1 and 2 can be swapped. */
bool
ix86_sse5_valid_op_p (rtx operands[], rtx insn ATTRIBUTE_UNUSED, int num,
- bool uses_oc0, int num_memory)
+ bool uses_oc0, int num_memory, bool commutative)
{
int mem_mask;
int mem_count;
/* format, example pmacsdd:
xmm1, xmm2, xmm3/mem, xmm1 */
+ if (commutative)
+ return (mem_mask == (1 << 2) || mem_mask == (1 << 1));
else
return (mem_mask == (1 << 2));
}
For the integer multiply/add instructions be more restrictive and
require operands[2] and operands[3] to be the memory operands. */
+ if (commutative)
+ return (mem_mask == ((1 << 1) | (1 << 3)) || ((1 << 2) | (1 << 3)));
else
return (mem_mask == ((1 << 2) | (1 << 3)));
}
#ifdef SUBTARGET_ATTRIBUTE_TABLE
SUBTARGET_ATTRIBUTE_TABLE,
#endif
+ /* ms_abi and sysv_abi calling convention function attributes. */
+ { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute },
+ { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute },
+ /* End element. */
{ NULL, 0, 0, false, false, false, NULL }
};
return 0;
}
+/* This function returns the calling abi specific va_list type node.
+ It returns the FNDECL specific va_list type. */
+
+tree
+ix86_fn_abi_va_list (tree fndecl)
+{
+ int abi;
+
+ if (!TARGET_64BIT)
+ return va_list_type_node;
+ gcc_assert (fndecl != NULL_TREE);
+ abi = ix86_function_abi ((const_tree) fndecl);
+
+ if (abi == MS_ABI)
+ return ms_va_list_type_node;
+ else
+ return sysv_va_list_type_node;
+}
+
+/* Returns the canonical va_list type specified by TYPE. If there
+ is no valid TYPE provided, it return NULL_TREE. */
+
+tree
+ix86_canonical_va_list_type (tree type)
+{
+ tree wtype, htype;
+
+ /* Resolve references and pointers to va_list type. */
+ if (INDIRECT_REF_P (type))
+ type = TREE_TYPE (type);
+ else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
+ type = TREE_TYPE (type);
+
+ if (TARGET_64BIT)
+ {
+ wtype = va_list_type_node;
+ gcc_assert (wtype != NULL_TREE);
+ htype = type;
+ if (TREE_CODE (wtype) == ARRAY_TYPE)
+ {
+ /* If va_list is an array type, the argument may have decayed
+ to a pointer type, e.g. by being passed to another function.
+ In that case, unwrap both types so that we can compare the
+ underlying records. */
+ if (TREE_CODE (htype) == ARRAY_TYPE
+ || POINTER_TYPE_P (htype))
+ {
+ wtype = TREE_TYPE (wtype);
+ htype = TREE_TYPE (htype);
+ }
+ }
+ if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+ return va_list_type_node;
+ wtype = sysv_va_list_type_node;
+ gcc_assert (wtype != NULL_TREE);
+ htype = type;
+ if (TREE_CODE (wtype) == ARRAY_TYPE)
+ {
+ /* If va_list is an array type, the argument may have decayed
+ to a pointer type, e.g. by being passed to another function.
+ In that case, unwrap both types so that we can compare the
+ underlying records. */
+ if (TREE_CODE (htype) == ARRAY_TYPE
+ || POINTER_TYPE_P (htype))
+ {
+ wtype = TREE_TYPE (wtype);
+ htype = TREE_TYPE (htype);
+ }
+ }
+ if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+ return sysv_va_list_type_node;
+ wtype = ms_va_list_type_node;
+ gcc_assert (wtype != NULL_TREE);
+ htype = type;
+ if (TREE_CODE (wtype) == ARRAY_TYPE)
+ {
+ /* If va_list is an array type, the argument may have decayed
+ to a pointer type, e.g. by being passed to another function.
+ In that case, unwrap both types so that we can compare the
+ underlying records. */
+ if (TREE_CODE (htype) == ARRAY_TYPE
+ || POINTER_TYPE_P (htype))
+ {
+ wtype = TREE_TYPE (wtype);
+ htype = TREE_TYPE (htype);
+ }
+ }
+ if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+ return ms_va_list_type_node;
+ return NULL_TREE;
+ }
+ return std_canonical_va_list_type (type);
+}
+
+/* Iterate through the target-specific builtin types for va_list.
+ IDX denotes the iterator, *PTREE is set to the result type of
+ the va_list builtin, and *PNAME to its internal type.
+ Returns zero if there is no element for this index, otherwise
+ IDX should be increased upon the next call.
+ Note, do not iterate a base builtin's name like __builtin_va_list.
+ Used from c_common_nodes_and_builtins. */
+
+int
+ix86_enum_va_list (int idx, const char **pname, tree *ptree)
+{
+ if (!TARGET_64BIT)
+ return 0;
+ switch (idx) {
+ case 0:
+ *ptree = ms_va_list_type_node;
+ *pname = "__builtin_ms_va_list";
+ break;
+ case 1:
+ *ptree = sysv_va_list_type_node;
+ *pname = "__builtin_sysv_va_list";
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
#undef TARGET_BUILD_BUILTIN_VA_LIST
#define TARGET_BUILD_BUILTIN_VA_LIST ix86_build_builtin_va_list
+#undef TARGET_FN_ABI_VA_LIST
+#define TARGET_FN_ABI_VA_LIST ix86_fn_abi_va_list
+
+#undef TARGET_CANONICAL_VA_LIST_TYPE
+#define TARGET_CANONICAL_VA_LIST_TYPE ix86_canonical_va_list_type
+
#undef TARGET_EXPAND_BUILTIN_VA_START
#define TARGET_EXPAND_BUILTIN_VA_START ix86_va_start
#undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST
#define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST x86_builtin_vectorization_cost
+#undef TARGET_SET_CURRENT_FUNCTION
+#define TARGET_SET_CURRENT_FUNCTION ix86_set_current_function
+
+#undef TARGET_OPTION_VALID_ATTRIBUTE_P
+#define TARGET_OPTION_VALID_ATTRIBUTE_P ix86_valid_option_attribute_p
+
+#undef TARGET_OPTION_SAVE
+#define TARGET_OPTION_SAVE ix86_function_specific_save
+
+#undef TARGET_OPTION_RESTORE
+#define TARGET_OPTION_RESTORE ix86_function_specific_restore
+
+#undef TARGET_OPTION_PRINT
+#define TARGET_OPTION_PRINT ix86_function_specific_print
+
+#undef TARGET_OPTION_CAN_INLINE_P
+#define TARGET_OPTION_CAN_INLINE_P ix86_can_inline_p
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
#include "gt-i386.h"