aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/i386
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/i386')
-rw-r--r--gcc/config/i386/avx2intrin.h2
-rw-r--r--gcc/config/i386/avxintrin.h1
-rw-r--r--gcc/config/i386/cpuid.h17
-rw-r--r--gcc/config/i386/darwin.h37
-rw-r--r--gcc/config/i386/darwin32-biarch.h58
-rw-r--r--gcc/config/i386/darwin64-biarch.h (renamed from gcc/config/i386/darwin64.h)5
-rw-r--r--gcc/config/i386/emmintrin.h2
-rw-r--r--gcc/config/i386/freebsd64.h5
-rw-r--r--gcc/config/i386/i386-builtin.def6
-rw-r--r--gcc/config/i386/i386.c257
-rw-r--r--gcc/config/i386/i386.md19
-rw-r--r--gcc/config/i386/sse.md48
-rw-r--r--gcc/config/i386/t-darwin32-biarch (renamed from gcc/config/i386/t-darwin)0
-rw-r--r--gcc/config/i386/t-darwin64-biarch (renamed from gcc/config/i386/t-darwin64)0
-rw-r--r--gcc/config/i386/t-freebsd6430
15 files changed, 274 insertions, 213 deletions
diff --git a/gcc/config/i386/avx2intrin.h b/gcc/config/i386/avx2intrin.h
index a56d3fc804a..f6a2555de33 100644
--- a/gcc/config/i386/avx2intrin.h
+++ b/gcc/config/i386/avx2intrin.h
@@ -258,7 +258,7 @@ extern __inline __m256i
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
_mm256_cmpgt_epi8 (__m256i __A, __m256i __B)
{
- return (__m256i) ((__v32qi)__A > (__v32qi)__B);
+ return (__m256i) ((__v32qs)__A > (__v32qs)__B);
}
extern __inline __m256i
diff --git a/gcc/config/i386/avxintrin.h b/gcc/config/i386/avxintrin.h
index 3891ffd099c..ca201b51be9 100644
--- a/gcc/config/i386/avxintrin.h
+++ b/gcc/config/i386/avxintrin.h
@@ -47,6 +47,7 @@ typedef unsigned int __v8su __attribute__ ((__vector_size__ (32)));
typedef short __v16hi __attribute__ ((__vector_size__ (32)));
typedef unsigned short __v16hu __attribute__ ((__vector_size__ (32)));
typedef char __v32qi __attribute__ ((__vector_size__ (32)));
+typedef signed char __v32qs __attribute__ ((__vector_size__ (32)));
typedef unsigned char __v32qu __attribute__ ((__vector_size__ (32)));
/* The Intel API is flexible enough that we must allow aliasing with other
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index a26c5e49795..962e7532a85 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -178,10 +178,27 @@
#define signature_VORTEX_ecx 0x436f5320
#define signature_VORTEX_edx 0x36387865
+#ifndef __x86_64__
+/* At least one cpu (Winchip 2) does not set %ebx and %ecx
+ for cpuid leaf 1. Forcibly zero the two registers before
+ calling cpuid as a precaution. */
+#define __cpuid(level, a, b, c, d) \
+ do { \
+ if (__builtin_constant_p (level) && (level) != 1) \
+ __asm__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level)); \
+ else \
+ __asm__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "1" (0), "2" (0)); \
+ } while (0)
+#else
#define __cpuid(level, a, b, c, d) \
__asm__ ("cpuid\n\t" \
: "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
: "0" (level))
+#endif
#define __cpuid_count(level, count, a, b, c, d) \
__asm__ ("cpuid\n\t" \
diff --git a/gcc/config/i386/darwin.h b/gcc/config/i386/darwin.h
index 53789e7c236..0603951d936 100644
--- a/gcc/config/i386/darwin.h
+++ b/gcc/config/i386/darwin.h
@@ -47,12 +47,13 @@ along with GCC; see the file COPYING3. If not see
image.
Therefore, for 64b exes at least, we must use the libunwind implementation,
even when static-libgcc is specified. We put libSystem first so that
- unwinder symbols are satisfied from there. */
+ unwinder symbols are satisfied from there.
+ We default to 64b for single-arch builds, so apply this unconditionally. */
#undef REAL_LIBGCC_SPEC
#define REAL_LIBGCC_SPEC \
"%{static-libgcc|static: \
- %{m64:%:version-compare(>= 10.6 mmacosx-version-min= -lSystem)} \
- -lgcc_eh -lgcc; \
+ %:version-compare(>= 10.6 mmacosx-version-min= -lSystem) \
+ -lgcc_eh -lgcc; \
shared-libgcc|fexceptions|fgnu-runtime: \
%:version-compare(!> 10.5 mmacosx-version-min= -lgcc_s.10.4) \
%:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \
@@ -130,7 +131,8 @@ extern int darwin_emit_branch_islands;
#undef CC1_SPEC
#define CC1_SPEC "%(cc1_cpu) \
%{!mkernel:%{!static:%{!mdynamic-no-pic:-fPIC}}} \
- %{g: %{!fno-eliminate-unused-debug-symbols: -feliminate-unused-debug-symbols }} " \
+ %{g: %{!fno-eliminate-unused-debug-symbols: -feliminate-unused-debug-symbols }} \
+ %{mx32:%eDarwin is not an mx32 platform}" \
DARWIN_CC1_SPEC
#undef ASM_SPEC
@@ -138,9 +140,6 @@ extern int darwin_emit_branch_islands;
" ASM_OPTIONS " -force_cpusubtype_ALL \
%{static}" ASM_MMACOSX_VERSION_MIN_SPEC
-#define DARWIN_ARCH_SPEC "%{m64:x86_64;:i386}"
-#define DARWIN_SUBARCH_SPEC DARWIN_ARCH_SPEC
-
#undef ENDFILE_SPEC
#define ENDFILE_SPEC \
"%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
@@ -148,12 +147,15 @@ extern int darwin_emit_branch_islands;
%{mpc64:crtprec64.o%s} \
%{mpc80:crtprec80.o%s}" TM_DESTRUCTOR
+/* We default to x86_64 for single-arch builds, bi-arch overrides. */
+#define DARWIN_ARCH_SPEC "x86_64"
+
#undef SUBTARGET_EXTRA_SPECS
#define SUBTARGET_EXTRA_SPECS \
DARWIN_EXTRA_SPECS \
- { "darwin_arch", DARWIN_ARCH_SPEC }, \
+ { "darwin_arch", DARWIN_ARCH_SPEC }, \
{ "darwin_crt2", "" }, \
- { "darwin_subarch", DARWIN_SUBARCH_SPEC },
+ { "darwin_subarch", DARWIN_ARCH_SPEC },
/* The Darwin assembler mostly follows AT&T syntax. */
#undef ASSEMBLER_DIALECT
@@ -219,6 +221,23 @@ extern int darwin_emit_branch_islands;
} \
} while (0)
+#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \
+ do { \
+ if ((LOG) != 0) { \
+ if ((MAX_SKIP) == 0 || (MAX_SKIP) >= (1 << (LOG)) - 1) \
+ fprintf ((FILE), "\t.p2align %d\n", (LOG)); \
+ else \
+ fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \
+ } \
+ } while (0)
+#endif
+
+/* Darwin x86 assemblers support the .ident directive. */
+
+#undef TARGET_ASM_OUTPUT_IDENT
+#define TARGET_ASM_OUTPUT_IDENT default_asm_output_ident_directive
+
/* Darwin profiling -- call mcount. */
#undef FUNCTION_PROFILER
#define FUNCTION_PROFILER(FILE, LABELNO) \
diff --git a/gcc/config/i386/darwin32-biarch.h b/gcc/config/i386/darwin32-biarch.h
new file mode 100644
index 00000000000..8dcc4a3b0b3
--- /dev/null
+++ b/gcc/config/i386/darwin32-biarch.h
@@ -0,0 +1,58 @@
+/* Target definitions for i386 running Darwin with a 32b host and supporting
+ a 64b multilib.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#undef DARWIN_ARCH_SPEC
+#define DARWIN_ARCH_SPEC "%{m64:x86_64;:i386}"
+
+/* WORKAROUND pr80556:
+ For x86_64 Darwin10 and later, the unwinder is in libunwind (redirected
+ from libSystem). This doesn't use the keymgr (see keymgr.c) and therefore
+ the calls that libgcc makes to obtain the KEYMGR_GCC3_DW2_OBJ_LIST are not
+ updated to include new images, and might not even be valid for a single
+ image.
+ Therefore, for 64b exes at least, we must use the libunwind implementation,
+ even when static-libgcc is specified. We put libSystem first so that
+ unwinder symbols are satisfied from there. */
+#undef REAL_LIBGCC_SPEC
+#define REAL_LIBGCC_SPEC \
+ "%{static-libgcc|static: \
+ %{m64:%:version-compare(>= 10.6 mmacosx-version-min= -lSystem)} \
+ -lgcc_eh -lgcc; \
+ shared-libgcc|fexceptions|fgnu-runtime: \
+ %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_s.10.4) \
+ %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \
+ %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_ext.10.4) \
+ %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \
+ -lgcc ; \
+ :%:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_s.10.4) \
+ %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \
+ %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_ext.10.4) \
+ %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \
+ -lgcc }"
+
+#undef DARWIN_SUBARCH_SPEC
+#define DARWIN_SUBARCH_SPEC DARWIN_ARCH_SPEC
+
+#undef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS \
+ DARWIN_EXTRA_SPECS \
+ { "darwin_arch", DARWIN_ARCH_SPEC }, \
+ { "darwin_crt2", "" }, \
+ { "darwin_subarch", DARWIN_SUBARCH_SPEC },
diff --git a/gcc/config/i386/darwin64.h b/gcc/config/i386/darwin64-biarch.h
index 87c4b8c14d3..5af7665c2a7 100644
--- a/gcc/config/i386/darwin64.h
+++ b/gcc/config/i386/darwin64-biarch.h
@@ -1,5 +1,6 @@
-/* Target definitions for x86_64 running Darwin.
- Copyright (C) 2006-2018 Free Software Foundation, Inc.
+/* Target definitions for x86_64 running Darwin with a 64b host supporting a
+ 32b multilib.
+ Copyright (C) 2006-2019 Free Software Foundation, Inc.
Contributed by Apple Computer Inc.
This file is part of GCC.
diff --git a/gcc/config/i386/emmintrin.h b/gcc/config/i386/emmintrin.h
index 040470f51d2..33e3b64b1d0 100644
--- a/gcc/config/i386/emmintrin.h
+++ b/gcc/config/i386/emmintrin.h
@@ -1296,7 +1296,7 @@ _mm_xor_si128 (__m128i __A, __m128i __B)
extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cmpeq_epi8 (__m128i __A, __m128i __B)
{
- return (__m128i) ((__v16qs)__A == (__v16qs)__B);
+ return (__m128i) ((__v16qi)__A == (__v16qi)__B);
}
extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
diff --git a/gcc/config/i386/freebsd64.h b/gcc/config/i386/freebsd64.h
index d7fbe946698..f4a4548595d 100644
--- a/gcc/config/i386/freebsd64.h
+++ b/gcc/config/i386/freebsd64.h
@@ -31,7 +31,7 @@ along with GCC; see the file COPYING3. If not see
#undef LINK_SPEC
#define LINK_SPEC "\
- %{m32:-m elf_i386_fbsd} \
+ %{m32:-m elf_i386_fbsd}%{!m32:-m elf_x86_64_fbsd} \
%{p:%nconsider using '-pg' instead of '-p' with gprof(1)} \
%{v:-V} \
%{assert*} %{R*} %{rpath*} %{defsym*} \
@@ -42,3 +42,6 @@ along with GCC; see the file COPYING3. If not see
-dynamic-linker %(fbsd_dynamic_linker) } \
%{static:-Bstatic}} \
%{symbolic:-Bsymbolic}"
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "m64" }
diff --git a/gcc/config/i386/i386-builtin.def b/gcc/config/i386/i386-builtin.def
index c14f7ef3ce2..fe23ab0b829 100644
--- a/gcc/config/i386/i386-builtin.def
+++ b/gcc/config/i386/i386-builtin.def
@@ -806,11 +806,11 @@ BDESC (OPTION_MASK_ISA_SSE3, CODE_FOR_sse3_hsubv2df3, "__builtin_ia32_hsubpd", I
/* SSSE3 */
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_absv16qi2, "__builtin_ia32_pabsb128", IX86_BUILTIN_PABSB128, UNKNOWN, (int) V16QI_FTYPE_V16QI)
-BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_absv8qi2, "__builtin_ia32_pabsb", IX86_BUILTIN_PABSB, UNKNOWN, (int) V8QI_FTYPE_V8QI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_absv8qi2, "__builtin_ia32_pabsb", IX86_BUILTIN_PABSB, UNKNOWN, (int) V8QI_FTYPE_V8QI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_absv8hi2, "__builtin_ia32_pabsw128", IX86_BUILTIN_PABSW128, UNKNOWN, (int) V8HI_FTYPE_V8HI)
-BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_absv4hi2, "__builtin_ia32_pabsw", IX86_BUILTIN_PABSW, UNKNOWN, (int) V4HI_FTYPE_V4HI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_absv4hi2, "__builtin_ia32_pabsw", IX86_BUILTIN_PABSW, UNKNOWN, (int) V4HI_FTYPE_V4HI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_absv4si2, "__builtin_ia32_pabsd128", IX86_BUILTIN_PABSD128, UNKNOWN, (int) V4SI_FTYPE_V4SI)
-BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_absv2si2, "__builtin_ia32_pabsd", IX86_BUILTIN_PABSD, UNKNOWN, (int) V2SI_FTYPE_V2SI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_absv2si2, "__builtin_ia32_pabsd", IX86_BUILTIN_PABSD, UNKNOWN, (int) V2SI_FTYPE_V2SI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phaddwv8hi3, "__builtin_ia32_phaddw128", IX86_BUILTIN_PHADDW128, UNKNOWN, (int) V8HI_FTYPE_V8HI_V8HI)
BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_phaddwv4hi3, "__builtin_ia32_phaddw", IX86_BUILTIN_PHADDW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index a88a29b51e6..7c92e698505 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -1024,16 +1024,8 @@ dimode_scalar_to_vector_candidate_p (rtx_insn *insn)
case ASHIFT:
case LSHIFTRT:
- if (!REG_P (XEXP (src, 1))
- && (!SUBREG_P (XEXP (src, 1))
- || SUBREG_BYTE (XEXP (src, 1)) != 0
- || !REG_P (SUBREG_REG (XEXP (src, 1))))
- && (!CONST_INT_P (XEXP (src, 1))
- || !IN_RANGE (INTVAL (XEXP (src, 1)), 0, 63)))
- return false;
-
- if (GET_MODE (XEXP (src, 1)) != QImode
- && !CONST_INT_P (XEXP (src, 1)))
+ if (!CONST_INT_P (XEXP (src, 1))
+ || !IN_RANGE (INTVAL (XEXP (src, 1)), 0, 63))
return false;
break;
@@ -1630,15 +1622,10 @@ dimode_scalar_chain::compute_convert_gain ()
{
if (CONST_INT_P (XEXP (src, 0)))
gain -= vector_const_cost (XEXP (src, 0));
- if (CONST_INT_P (XEXP (src, 1)))
- {
- gain += ix86_cost->shift_const;
- if (INTVAL (XEXP (src, 1)) >= 32)
- gain -= COSTS_N_INSNS (1);
- }
- else
- /* Additional gain for omitting two CMOVs. */
- gain += ix86_cost->shift_var + COSTS_N_INSNS (2);
+
+ gain += ix86_cost->shift_const;
+ if (INTVAL (XEXP (src, 1)) >= 32)
+ gain -= COSTS_N_INSNS (1);
}
else if (GET_CODE (src) == PLUS
|| GET_CODE (src) == MINUS
@@ -1754,60 +1741,14 @@ dimode_scalar_chain::make_vector_copies (unsigned regno)
{
rtx reg = regno_reg_rtx[regno];
rtx vreg = gen_reg_rtx (DImode);
- bool count_reg = false;
df_ref ref;
for (ref = DF_REG_DEF_CHAIN (regno); ref; ref = DF_REF_NEXT_REG (ref))
if (!bitmap_bit_p (insns, DF_REF_INSN_UID (ref)))
{
- df_ref use;
-
- /* Detect the count register of a shift instruction. */
- for (use = DF_REG_USE_CHAIN (regno); use; use = DF_REF_NEXT_REG (use))
- if (bitmap_bit_p (insns, DF_REF_INSN_UID (use)))
- {
- rtx_insn *insn = DF_REF_INSN (use);
- rtx def_set = single_set (insn);
-
- gcc_assert (def_set);
-
- rtx src = SET_SRC (def_set);
-
- if ((GET_CODE (src) == ASHIFT
- || GET_CODE (src) == ASHIFTRT
- || GET_CODE (src) == LSHIFTRT)
- && !CONST_INT_P (XEXP (src, 1))
- && reg_or_subregno (XEXP (src, 1)) == regno)
- count_reg = true;
- }
-
start_sequence ();
- if (count_reg)
- {
- rtx qreg = gen_lowpart (QImode, reg);
- rtx tmp = gen_reg_rtx (SImode);
-
- if (TARGET_ZERO_EXTEND_WITH_AND
- && optimize_function_for_speed_p (cfun))
- {
- emit_move_insn (tmp, const0_rtx);
- emit_insn (gen_movstrictqi
- (gen_lowpart (QImode, tmp), qreg));
- }
- else
- emit_insn (gen_rtx_SET
- (tmp, gen_rtx_ZERO_EXTEND (SImode, qreg)));
-
- if (!TARGET_INTER_UNIT_MOVES_TO_VEC)
- {
- rtx slot = assign_386_stack_local (SImode, SLOT_STV_TEMP);
- emit_move_insn (slot, tmp);
- tmp = copy_rtx (slot);
- }
- emit_insn (gen_zero_extendsidi2 (vreg, tmp));
- }
- else if (!TARGET_INTER_UNIT_MOVES_TO_VEC)
+ if (!TARGET_INTER_UNIT_MOVES_TO_VEC)
{
rtx tmp = assign_386_stack_local (DImode, SLOT_STV_TEMP);
emit_move_insn (adjust_address (tmp, SImode, 0),
@@ -1855,22 +1796,8 @@ dimode_scalar_chain::make_vector_copies (unsigned regno)
if (bitmap_bit_p (insns, DF_REF_INSN_UID (ref)))
{
rtx_insn *insn = DF_REF_INSN (ref);
- if (count_reg)
- {
- rtx def_set = single_set (insn);
- gcc_assert (def_set);
- rtx src = SET_SRC (def_set);
-
- if ((GET_CODE (src) == ASHIFT
- || GET_CODE (src) == ASHIFTRT
- || GET_CODE (src) == LSHIFTRT)
- && !CONST_INT_P (XEXP (src, 1))
- && reg_or_subregno (XEXP (src, 1)) == regno)
- XEXP (src, 1) = vreg;
- }
- else
- replace_with_subreg_in_insn (insn, reg, vreg);
+ replace_with_subreg_in_insn (insn, reg, vreg);
if (dump_file)
fprintf (dump_file, " Replaced r%d with r%d in insn %d\n",
@@ -1973,42 +1900,7 @@ dimode_scalar_chain::convert_reg (unsigned regno)
rtx src = SET_SRC (def_set);
rtx dst = SET_DEST (def_set);
- if ((GET_CODE (src) == ASHIFT
- || GET_CODE (src) == ASHIFTRT
- || GET_CODE (src) == LSHIFTRT)
- && !CONST_INT_P (XEXP (src, 1))
- && reg_or_subregno (XEXP (src, 1)) == regno)
- {
- rtx tmp2 = gen_reg_rtx (V2DImode);
-
- start_sequence ();
-
- if (TARGET_SSE4_1)
- emit_insn (gen_sse4_1_zero_extendv2qiv2di2
- (tmp2, gen_rtx_SUBREG (V16QImode, reg, 0)));
- else
- {
- rtx vec_cst
- = gen_rtx_CONST_VECTOR (V2DImode,
- gen_rtvec (2, GEN_INT (0xff),
- const0_rtx));
- vec_cst
- = validize_mem (force_const_mem (V2DImode, vec_cst));
-
- emit_insn (gen_rtx_SET
- (tmp2,
- gen_rtx_AND (V2DImode,
- gen_rtx_SUBREG (V2DImode, reg, 0),
- vec_cst)));
- }
- rtx_insn *seq = get_insns ();
- end_sequence ();
-
- emit_insn_before (seq, insn);
-
- XEXP (src, 1) = gen_rtx_SUBREG (DImode, tmp2, 0);
- }
- else if (!MEM_P (dst) || !REG_P (src))
+ if (!MEM_P (dst) || !REG_P (src))
replace_with_subreg_in_insn (insn, reg, reg);
bitmap_clear_bit (conv, INSN_UID (insn));
@@ -4958,6 +4850,12 @@ ix86_option_override_internal (bool main_args_p,
opts->x_param_values,
opts_set->x_param_values);
+ /* PR86952: jump table usage with retpolines is slow.
+ The PR provides some numbers about the slowness. */
+ if (ix86_indirect_branch != indirect_branch_keep
+ && !opts_set->x_flag_jump_tables)
+ opts->x_flag_jump_tables = 0;
+
return true;
}
@@ -18121,6 +18019,7 @@ print_reg (rtx x, int code, FILE *file)
; -- print a semicolon (after prefixes due to bug in older gas).
~ -- print "i" if TARGET_AVX2, "f" otherwise.
^ -- print addr32 prefix if TARGET_64BIT and Pmode != word_mode
+ M -- print addr32 prefix for TARGET_X32 with VSIB address.
! -- print MPX prefix for jxx/call/ret instructions if required.
*/
@@ -18668,6 +18567,26 @@ ix86_print_operand (FILE *file, rtx x, int code)
putc (TARGET_AVX2 ? 'i' : 'f', file);
return;
+ case 'M':
+ if (TARGET_X32)
+ {
+ /* NB: 32-bit indices in VSIB address are sign-extended
+ to 64 bits. In x32, if 32-bit address 0xf7fa3010 is
+ sign-extended to 0xfffffffff7fa3010 which is invalid
+ address. Add addr32 prefix if there is no base
+ register nor symbol. */
+ bool ok;
+ struct ix86_address parts;
+ ok = ix86_decompose_address (x, &parts);
+ gcc_assert (ok && parts.index == NULL_RTX);
+ if (parts.base == NULL_RTX
+ && (parts.disp == NULL_RTX
+ || !symbolic_operand (parts.disp,
+ GET_MODE (parts.disp))))
+ fputs ("addr32 ", file);
+ }
+ return;
+
case '^':
if (TARGET_64BIT && Pmode != word_mode)
fputs ("addr32 ", file);
@@ -24062,6 +23981,8 @@ ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code code, rtx cmp_op0,
else
{
code = is_min ? SMIN : SMAX;
+ if (MEM_P (if_true) && MEM_P (if_false))
+ if_true = force_reg (mode, if_true);
tmp = gen_rtx_fmt_ee (code, mode, if_true, if_false);
}
@@ -28757,6 +28678,25 @@ ix86_nopic_noplt_attribute_p (rtx call_op)
return false;
}
+/* Helper to output the jmp/call. */
+static void
+ix86_output_jmp_thunk_or_indirect (const char *thunk_name,
+ enum indirect_thunk_prefix need_prefix,
+ const int regno)
+{
+ if (thunk_name != NULL)
+ {
+ if (need_prefix == indirect_thunk_prefix_bnd)
+ fprintf (asm_out_file, "\tbnd jmp\t");
+ else
+ fprintf (asm_out_file, "\tjmp\t");
+ assemble_name (asm_out_file, thunk_name);
+ putc ('\n', asm_out_file);
+ }
+ else
+ output_indirect_thunk (need_prefix, regno);
+}
+
/* Output indirect branch via a call and return thunk. CALL_OP is a
register which contains the branch target. XASM is the assembly
template for CALL_OP. Branch is a tail call if SIBCALL_P is true.
@@ -28798,25 +28738,17 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
thunk_name = NULL;
if (sibcall_p)
- {
- if (thunk_name != NULL)
- {
- if (need_prefix == indirect_thunk_prefix_bnd)
- fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
- else
- fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
- }
- else
- output_indirect_thunk (need_prefix, regno);
- }
+ ix86_output_jmp_thunk_or_indirect (thunk_name, need_prefix, regno);
else
{
if (thunk_name != NULL)
{
if (need_prefix == indirect_thunk_prefix_bnd)
- fprintf (asm_out_file, "\tbnd call\t%s\n", thunk_name);
+ fprintf (asm_out_file, "\tbnd call\t");
else
- fprintf (asm_out_file, "\tcall\t%s\n", thunk_name);
+ fprintf (asm_out_file, "\tcall\t");
+ assemble_name (asm_out_file, thunk_name);
+ putc ('\n', asm_out_file);
return;
}
@@ -28840,15 +28772,7 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
- if (thunk_name != NULL)
- {
- if (need_prefix == indirect_thunk_prefix_bnd)
- fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
- else
- fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
- }
- else
- output_indirect_thunk (need_prefix, regno);
+ ix86_output_jmp_thunk_or_indirect (thunk_name, need_prefix, regno);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
@@ -28913,15 +28837,7 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
if (sibcall_p)
{
output_asm_insn (push_buf, &call_op);
- if (thunk_name != NULL)
- {
- if (need_prefix == indirect_thunk_prefix_bnd)
- fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
- else
- fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
- }
- else
- output_indirect_thunk (need_prefix, regno);
+ ix86_output_jmp_thunk_or_indirect (thunk_name, need_prefix, regno);
}
else
{
@@ -28980,15 +28896,7 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
output_asm_insn (push_buf, &call_op);
- if (thunk_name != NULL)
- {
- if (need_prefix == indirect_thunk_prefix_bnd)
- fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
- else
- fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
- }
- else
- output_indirect_thunk (need_prefix, regno);
+ ix86_output_jmp_thunk_or_indirect (thunk_name, need_prefix, regno);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
@@ -29057,13 +28965,15 @@ ix86_output_function_return (bool long_p)
if (need_prefix == indirect_thunk_prefix_bnd)
{
indirect_return_bnd_needed |= need_thunk;
- fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
+ fprintf (asm_out_file, "\tbnd jmp\t");
}
else
{
indirect_return_needed |= need_thunk;
- fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
+ fprintf (asm_out_file, "\tjmp\t");
}
+ assemble_name (asm_out_file, thunk_name);
+ putc ('\n', asm_out_file);
}
else
output_indirect_thunk (need_prefix, INVALID_REGNUM);
@@ -29104,7 +29014,7 @@ ix86_output_indirect_function_return (rtx ret_op)
indirect_return_via_cx_bnd = true;
indirect_thunks_bnd_used |= 1 << CX_REG;
}
- fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
+ fprintf (asm_out_file, "\tbnd jmp\t");
}
else
{
@@ -29113,8 +29023,10 @@ ix86_output_indirect_function_return (rtx ret_op)
indirect_return_via_cx = true;
indirect_thunks_used |= 1 << CX_REG;
}
- fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
+ fprintf (asm_out_file, "\tjmp\t");
}
+ assemble_name (asm_out_file, thunk_name);
+ putc ('\n', asm_out_file);
}
else
output_indirect_thunk (need_prefix, regno);
@@ -32923,6 +32835,7 @@ make_resolver_func (const tree default_decl,
}
/* Build result decl and add to function_decl. */
t = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, ptr_type_node);
+ DECL_CONTEXT (t) = decl;
DECL_ARTIFICIAL (t) = 1;
DECL_IGNORED_P (t) = 1;
DECL_RESULT (decl) = t;
@@ -45705,8 +45618,10 @@ ix86_expand_floorceildf_32 (rtx operand0, rtx operand1, bool do_floor)
x2 -= 1;
Compensate. Ceil:
if (x2 < x)
- x2 -= -1;
- return x2;
+ x2 += 1;
+ if (HONOR_SIGNED_ZEROS (mode))
+ x2 = copysign (x2, x);
+ return x2;
*/
machine_mode mode = GET_MODE (operand0);
rtx xa, TWO52, tmp, one, res, mask;
@@ -45732,17 +45647,16 @@ ix86_expand_floorceildf_32 (rtx operand0, rtx operand1, bool do_floor)
/* xa = copysign (xa, operand1) */
ix86_sse_copysign_to_positive (xa, xa, res, mask);
- /* generate 1.0 or -1.0 */
- one = force_reg (mode,
- const_double_from_real_value (do_floor
- ? dconst1 : dconstm1, mode));
+ /* generate 1.0 */
+ one = force_reg (mode, const_double_from_real_value (dconst1, mode));
/* Compensate: xa = xa - (xa > operand1 ? 1 : 0) */
tmp = ix86_expand_sse_compare_mask (UNGT, xa, res, !do_floor);
emit_insn (gen_rtx_SET (tmp, gen_rtx_AND (mode, one, tmp)));
- /* We always need to subtract here to preserve signed zero. */
- tmp = expand_simple_binop (mode, MINUS,
+ tmp = expand_simple_binop (mode, do_floor ? MINUS : PLUS,
xa, tmp, NULL_RTX, 0, OPTAB_DIRECT);
+ if (!do_floor && HONOR_SIGNED_ZEROS (mode))
+ ix86_sse_copysign_to_positive (tmp, tmp, res, mask);
emit_move_insn (res, tmp);
emit_label (label);
@@ -46379,7 +46293,8 @@ static bool
expand_vec_perm_blend (struct expand_vec_perm_d *d)
{
machine_mode mmode, vmode = d->vmode;
- unsigned i, mask, nelt = d->nelt;
+ unsigned i, nelt = d->nelt;
+ unsigned HOST_WIDE_INT mask;
rtx target, op0, op1, maskop, x;
rtx rperm[32], vperm;
@@ -46433,7 +46348,7 @@ expand_vec_perm_blend (struct expand_vec_perm_d *d)
case E_V16SImode:
case E_V8DImode:
for (i = 0; i < nelt; ++i)
- mask |= (d->perm[i] >= nelt) << i;
+ mask |= ((unsigned HOST_WIDE_INT) (d->perm[i] >= nelt)) << i;
break;
case E_V2DImode:
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 7691160c0c4..2bb58236d88 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -8942,7 +8942,24 @@
[(parallel [(set (match_dup 0)
(zero_extend:DI (and:SI (match_dup 1) (match_dup 2))))
(clobber (reg:CC FLAGS_REG))])]
- "operands[2] = gen_lowpart (SImode, operands[2]);")
+{
+ if (GET_CODE (operands[2]) == SYMBOL_REF
+ || GET_CODE (operands[2]) == LABEL_REF)
+ {
+ operands[2] = shallow_copy_rtx (operands[2]);
+ PUT_MODE (operands[2], SImode);
+ }
+ else if (GET_CODE (operands[2]) == CONST)
+ {
+ /* (const:DI (plus:DI (symbol_ref:DI ("...")) (const_int N))) */
+ operands[2] = copy_rtx (operands[2]);
+ PUT_MODE (operands[2], SImode);
+ PUT_MODE (XEXP (operands[2], 0), SImode);
+ PUT_MODE (XEXP (XEXP (operands[2], 0), 0), SImode);
+ }
+ else
+ operands[2] = gen_lowpart (SImode, operands[2]);
+})
;; See comment for addsi_1_zext why we do use nonimmediate_operand
(define_insn "*andsi_1_zext"
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index 0a75bd10976..5c6d2948d65 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -15172,7 +15172,7 @@
}
})
-(define_insn "abs<mode>2"
+(define_insn "ssse3_abs<mode>2"
[(set (match_operand:MMXMODEI 0 "register_operand" "=y")
(abs:MMXMODEI
(match_operand:MMXMODEI 1 "nonimmediate_operand" "ym")))]
@@ -16271,9 +16271,9 @@
case 3:
/* %X5 so that we don't emit any *WORD PTR for -masm=intel, as
gas changed what it requires incompatibly. */
- return "vgatherpf0<ssemodesuffix>ps\t{%5%{%0%}|%X5%{%0%}}";
+ return "%M2vgatherpf0<ssemodesuffix>ps\t{%5%{%0%}|%X5%{%0%}}";
case 2:
- return "vgatherpf1<ssemodesuffix>ps\t{%5%{%0%}|%X5%{%0%}}";
+ return "%M2vgatherpf1<ssemodesuffix>ps\t{%5%{%0%}|%X5%{%0%}}";
default:
gcc_unreachable ();
}
@@ -16318,9 +16318,9 @@
case 3:
/* %X5 so that we don't emit any *WORD PTR for -masm=intel, as
gas changed what it requires incompatibly. */
- return "vgatherpf0<ssemodesuffix>pd\t{%5%{%0%}|%X5%{%0%}}";
+ return "%M2vgatherpf0<ssemodesuffix>pd\t{%5%{%0%}|%X5%{%0%}}";
case 2:
- return "vgatherpf1<ssemodesuffix>pd\t{%5%{%0%}|%X5%{%0%}}";
+ return "%M2vgatherpf1<ssemodesuffix>pd\t{%5%{%0%}|%X5%{%0%}}";
default:
gcc_unreachable ();
}
@@ -16366,10 +16366,10 @@
case 7:
/* %X5 so that we don't emit any *WORD PTR for -masm=intel, as
gas changed what it requires incompatibly. */
- return "vscatterpf0<ssemodesuffix>ps\t{%5%{%0%}|%X5%{%0%}}";
+ return "%M2vscatterpf0<ssemodesuffix>ps\t{%5%{%0%}|%X5%{%0%}}";
case 2:
case 6:
- return "vscatterpf1<ssemodesuffix>ps\t{%5%{%0%}|%X5%{%0%}}";
+ return "%M2vscatterpf1<ssemodesuffix>ps\t{%5%{%0%}|%X5%{%0%}}";
default:
gcc_unreachable ();
}
@@ -16415,10 +16415,10 @@
case 7:
/* %X5 so that we don't emit any *WORD PTR for -masm=intel, as
gas changed what it requires incompatibly. */
- return "vscatterpf0<ssemodesuffix>pd\t{%5%{%0%}|%X5%{%0%}}";
+ return "%M2vscatterpf0<ssemodesuffix>pd\t{%5%{%0%}|%X5%{%0%}}";
case 2:
case 6:
- return "vscatterpf1<ssemodesuffix>pd\t{%5%{%0%}|%X5%{%0%}}";
+ return "%M2vscatterpf1<ssemodesuffix>pd\t{%5%{%0%}|%X5%{%0%}}";
default:
gcc_unreachable ();
}
@@ -19157,7 +19157,7 @@
UNSPEC_GATHER))
(clobber (match_scratch:VEC_GATHER_MODE 1 "=&x"))]
"TARGET_AVX2"
- "v<sseintprefix>gatherd<ssemodesuffix>\t{%1, %7, %0|%0, %7, %1}"
+ "%M3v<sseintprefix>gatherd<ssemodesuffix>\t{%1, %7, %0|%0, %7, %1}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "vex")
(set_attr "mode" "<sseinsnmode>")])
@@ -19177,7 +19177,7 @@
UNSPEC_GATHER))
(clobber (match_scratch:VEC_GATHER_MODE 1 "=&x"))]
"TARGET_AVX2"
- "v<sseintprefix>gatherd<ssemodesuffix>\t{%1, %6, %0|%0, %6, %1}"
+ "%M2v<sseintprefix>gatherd<ssemodesuffix>\t{%1, %6, %0|%0, %6, %1}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "vex")
(set_attr "mode" "<sseinsnmode>")])
@@ -19218,7 +19218,7 @@
UNSPEC_GATHER))
(clobber (match_scratch:VEC_GATHER_MODE 1 "=&x"))]
"TARGET_AVX2"
- "v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %7, %2|%2, %7, %5}"
+ "%M3v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %7, %2|%2, %7, %5}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "vex")
(set_attr "mode" "<sseinsnmode>")])
@@ -19240,8 +19240,8 @@
"TARGET_AVX2"
{
if (<MODE>mode != <VEC_GATHER_SRCDI>mode)
- return "v<sseintprefix>gatherq<ssemodesuffix>\t{%4, %6, %x0|%x0, %6, %4}";
- return "v<sseintprefix>gatherq<ssemodesuffix>\t{%4, %6, %0|%0, %6, %4}";
+ return "%M2v<sseintprefix>gatherq<ssemodesuffix>\t{%4, %6, %x0|%x0, %6, %4}";
+ return "%M2v<sseintprefix>gatherq<ssemodesuffix>\t{%4, %6, %0|%0, %6, %4}";
}
[(set_attr "type" "ssemov")
(set_attr "prefix" "vex")
@@ -19265,7 +19265,7 @@
(const_int 2) (const_int 3)])))
(clobber (match_scratch:VI4F_256 1 "=&x"))]
"TARGET_AVX2"
- "v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %7, %0|%0, %7, %5}"
+ "%M3v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %7, %0|%0, %7, %5}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "vex")
(set_attr "mode" "<sseinsnmode>")])
@@ -19288,7 +19288,7 @@
(const_int 2) (const_int 3)])))
(clobber (match_scratch:VI4F_256 1 "=&x"))]
"TARGET_AVX2"
- "v<sseintprefix>gatherq<ssemodesuffix>\t{%4, %6, %0|%0, %6, %4}"
+ "%M2v<sseintprefix>gatherq<ssemodesuffix>\t{%4, %6, %0|%0, %6, %4}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "vex")
(set_attr "mode" "<sseinsnmode>")])
@@ -19328,7 +19328,7 @@
"TARGET_AVX512F"
;; %X6 so that we don't emit any *WORD PTR for -masm=intel, as
;; gas changed what it requires incompatibly.
- "v<sseintprefix>gatherd<ssemodesuffix>\t{%6, %0%{%2%}|%0%{%2%}, %X6}"
+ "%M4v<sseintprefix>gatherd<ssemodesuffix>\t{%6, %0%{%2%}|%0%{%2%}, %X6}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
@@ -19349,7 +19349,7 @@
"TARGET_AVX512F"
;; %X5 so that we don't emit any *WORD PTR for -masm=intel, as
;; gas changed what it requires incompatibly.
- "v<sseintprefix>gatherd<ssemodesuffix>\t{%5, %0%{%1%}|%0%{%1%}, %X5}"
+ "%M3v<sseintprefix>gatherd<ssemodesuffix>\t{%5, %0%{%1%}|%0%{%1%}, %X5}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
@@ -19390,7 +19390,7 @@
"TARGET_AVX512F"
;; %X6 so that we don't emit any *WORD PTR for -masm=intel, as
;; gas changed what it requires incompatibly.
- "v<sseintprefix>gatherq<ssemodesuffix>\t{%6, %1%{%2%}|%1%{%2%}, %X6}"
+ "%M4v<sseintprefix>gatherq<ssemodesuffix>\t{%6, %1%{%2%}|%1%{%2%}, %X6}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
@@ -19415,11 +19415,11 @@
if (<MODE>mode != <VEC_GATHER_SRCDI>mode)
{
if (<MODE_SIZE> != 64)
- return "v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %x0%{%1%}|%x0%{%1%}, %X5}";
+ return "%M3v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %x0%{%1%}|%x0%{%1%}, %X5}";
else
- return "v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %t0%{%1%}|%t0%{%1%}, %X5}";
+ return "%M3v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %t0%{%1%}|%t0%{%1%}, %X5}";
}
- return "v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %0%{%1%}|%0%{%1%}, %X5}";
+ return "%M3v<sseintprefix>gatherq<ssemodesuffix>\t{%5, %0%{%1%}|%0%{%1%}, %X5}";
}
[(set_attr "type" "ssemov")
(set_attr "prefix" "evex")
@@ -19458,7 +19458,7 @@
"TARGET_AVX512F"
;; %X5 so that we don't emit any *WORD PTR for -masm=intel, as
;; gas changed what it requires incompatibly.
- "v<sseintprefix>scatterd<ssemodesuffix>\t{%3, %5%{%1%}|%X5%{%1%}, %3}"
+ "%M0v<sseintprefix>scatterd<ssemodesuffix>\t{%3, %5%{%1%}|%X5%{%1%}, %3}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
@@ -19496,7 +19496,7 @@
"TARGET_AVX512F"
;; %X5 so that we don't emit any *WORD PTR for -masm=intel, as
;; gas changed what it requires incompatibly.
- "v<sseintprefix>scatterq<ssemodesuffix>\t{%3, %5%{%1%}|%X5%{%1%}, %3}"
+ "%M0v<sseintprefix>scatterq<ssemodesuffix>\t{%3, %5%{%1%}|%X5%{%1%}, %3}"
[(set_attr "type" "ssemov")
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
diff --git a/gcc/config/i386/t-darwin b/gcc/config/i386/t-darwin32-biarch
index bf44504d4fd..bf44504d4fd 100644
--- a/gcc/config/i386/t-darwin
+++ b/gcc/config/i386/t-darwin32-biarch
diff --git a/gcc/config/i386/t-darwin64 b/gcc/config/i386/t-darwin64-biarch
index 6a6b22f1ee5..6a6b22f1ee5 100644
--- a/gcc/config/i386/t-darwin64
+++ b/gcc/config/i386/t-darwin64-biarch
diff --git a/gcc/config/i386/t-freebsd64 b/gcc/config/i386/t-freebsd64
new file mode 100644
index 00000000000..0dd05d479ac
--- /dev/null
+++ b/gcc/config/i386/t-freebsd64
@@ -0,0 +1,30 @@
+# Copyright (C) 2019 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# The 32-bit libraries are found in /usr/lib32
+
+# To support i386 and x86-64, the directory structrue
+# should be:
+#
+# /lib has x86-64 libraries.
+# /lib32 has i386 libraries.
+#
+
+MULTILIB_OPTIONS = m32
+MULTILIB_DIRNAMES = 32
+MULTILIB_OSDIRNAMES = ../lib32