Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -3256,18 +3256,24 @@ class X86_64TargetInfo : public X86TargetInfo { public: X86_64TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) { - LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + const bool IsX32{getTriple().getEnvironment() == llvm::Triple::GNUX32}; + LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64; LongDoubleWidth = 128; LongDoubleAlign = 128; LargeArrayMinWidth = 128; LargeArrayAlign = 128; SuitableAlign = 128; - IntMaxType = SignedLong; - UIntMaxType = UnsignedLong; - Int64Type = SignedLong; + SizeType = IsX32 ? UnsignedInt : UnsignedLong; + PtrDiffType = IsX32 ? SignedInt : SignedLong; + IntPtrType = IsX32 ? SignedInt : SignedLong; + IntMaxType = IsX32 ? SignedLongLong : SignedLong; + UIntMaxType = IsX32 ? UnsignedLongLong : UnsignedLong; + Int64Type = IsX32 ? SignedLongLong : SignedLong; RegParmMax = 6; - DescriptionString = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"; + DescriptionString = (IsX32) + ? "e-m:e-" "p:32:32-" "i64:64-f80:128-n8:16:32:64-S128" + : "e-m:e-" "i64:64-f80:128-n8:16:32:64-S128"; // Use fpret only for long double. RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -1341,8 +1341,9 @@ "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux", - "x86_64-linux-android" + "x86_64-linux-android", "x86_64-unknown-linux" }; + static const char *const X32LibDirs[] = { "/libx32" }; static const char *const X86LibDirs[] = { "/lib32", "/lib" }; static const char *const X86Triples[] = { "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu", @@ -1445,10 +1446,19 @@ X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); TripleAliases.append(X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples)); - BiarchLibDirs.append(X86LibDirs, - X86LibDirs + llvm::array_lengthof(X86LibDirs)); - BiarchTripleAliases.append(X86Triples, - X86Triples + llvm::array_lengthof(X86Triples)); + // x32 is always available when x86_64 is available, so adding it as secondary + // arch with x86_64 triples + if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) { + BiarchLibDirs.append(X32LibDirs, + X32LibDirs + llvm::array_lengthof(X32LibDirs)); + BiarchTripleAliases.append(X86_64Triples, + X86_64Triples + llvm::array_lengthof(X86_64Triples)); + } else { + BiarchLibDirs.append(X86LibDirs, + X86LibDirs + llvm::array_lengthof(X86LibDirs)); + BiarchTripleAliases.append(X86Triples, + X86Triples + llvm::array_lengthof(X86Triples)); + } break; case llvm::Triple::x86: LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs)); @@ -1935,47 +1945,64 @@ Multilib Alt64 = Multilib() .gccSuffix("/64") .includeSuffix("/64") - .flag("-m32").flag("+m64"); + .flag("-m32").flag("+m64").flag("-mx32"); Multilib Alt32 = Multilib() .gccSuffix("/32") .includeSuffix("/32") - .flag("+m32").flag("-m64"); + .flag("+m32").flag("-m64").flag("-mx32"); + Multilib Altx32 = Multilib() + .gccSuffix("/x32") + .includeSuffix("/x32") + .flag("-m32").flag("-m64").flag("+mx32"); FilterNonExistent NonExistent(Path); - // Decide whether the default multilib is 32bit, correcting for - // when the default multilib and the alternate appear backwards - bool DefaultIs32Bit; + // Determine default multilib from: 32, 64, x32 + // Also handle cases such as 64 on 32, 32 on 64, etc. + enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN; + const bool isX32 {TargetTriple.getEnvironment() == llvm::Triple::GNUX32}; if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) - DefaultIs32Bit = false; - else if (TargetTriple.isArch64Bit() && !NonExistent(Alt64)) - DefaultIs32Bit = true; + Want = WANT64; + else if (TargetTriple.isArch64Bit() && isX32 && !NonExistent(Altx32)) + Want = WANT64; + else if (TargetTriple.isArch64Bit() && !isX32 && !NonExistent(Alt64)) + Want = WANT32; else { - if (NeedsBiarchSuffix) - DefaultIs32Bit = TargetTriple.isArch64Bit(); + if (TargetTriple.isArch32Bit()) + Want = NeedsBiarchSuffix ? WANT64 : WANT32; + else if (isX32) + Want = NeedsBiarchSuffix ? WANT64 : WANTX32; else - DefaultIs32Bit = TargetTriple.isArch32Bit(); + Want = NeedsBiarchSuffix ? WANT32 : WANT64; } - if (DefaultIs32Bit) - Default.flag("+m32").flag("-m64"); + if (Want == WANT32) + Default.flag("+m32").flag("-m64").flag("-mx32"); + else if (Want == WANT64) + Default.flag("-m32").flag("+m64").flag("-mx32"); + else if (Want == WANTX32) + Default.flag("-m32").flag("-m64").flag("+mx32"); else - Default.flag("-m32").flag("+m64"); + return false; Result.Multilibs.push_back(Default); Result.Multilibs.push_back(Alt64); Result.Multilibs.push_back(Alt32); + Result.Multilibs.push_back(Altx32); Result.Multilibs.FilterOut(NonExistent); Multilib::flags_list Flags; - addMultilibFlag(TargetTriple.isArch64Bit(), "m64", Flags); + addMultilibFlag(TargetTriple.isArch64Bit() && !isX32, "m64", Flags); addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); + addMultilibFlag(TargetTriple.isArch64Bit() && isX32, "mx32", Flags); if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) return false; - if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32) + if (Result.SelectedMultilib == Alt64 || + Result.SelectedMultilib == Alt32 || + Result.SelectedMultilib == Altx32) Result.BiarchSibling = Default; return true; @@ -2889,7 +2916,9 @@ return "i386-linux-gnu"; return TargetTriple.str(); case llvm::Triple::x86_64: - if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu")) + // We don't want this for x32, otherwise it will match x86_64 libs + if (TargetTriple.getEnvironment() != llvm::Triple::GNUX32 && + llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu")) return "x86_64-linux-gnu"; return TargetTriple.str(); case llvm::Triple::arm64: @@ -2953,6 +2982,10 @@ Triple.getArch() == llvm::Triple::ppc) return "lib32"; + if (Triple.getArch() == llvm::Triple::x86_64 && + Triple.getEnvironment() == llvm::Triple::GNUX32) + return "libx32"; + return Triple.isArch32Bit() ? "lib" : "lib64"; } Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -6741,7 +6741,10 @@ if (getToolChain().getArch() == llvm::Triple::x86) { CmdArgs.push_back("--32"); } else if (getToolChain().getArch() == llvm::Triple::x86_64) { - CmdArgs.push_back("--64"); + if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32) + CmdArgs.push_back("--x32"); + else + CmdArgs.push_back("--64"); } else if (getToolChain().getArch() == llvm::Triple::ppc) { CmdArgs.push_back("-a32"); CmdArgs.push_back("-mppc"); @@ -6938,6 +6941,9 @@ return "/lib64/ld64.so.2"; else if (ToolChain.getArch() == llvm::Triple::sparcv9) return "/lib64/ld-linux.so.2"; + else if (ToolChain.getArch() == llvm::Triple::x86_64 && + ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUX32) + return "/libx32/ld-linux-x32.so.2"; else return "/lib64/ld-linux-x86-64.so.2"; } @@ -7048,6 +7054,9 @@ } else if (ToolChain.getArch() == llvm::Triple::systemz) CmdArgs.push_back("elf64_s390"); + else if (ToolChain.getArch() == llvm::Triple::x86_64 && + ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUX32) + CmdArgs.push_back("elf32_x86_64"); else CmdArgs.push_back("elf_x86_64"); Index: test/Driver/cross-linux.c =================================================================== --- test/Driver/cross-linux.c +++ test/Driver/cross-linux.c @@ -16,6 +16,14 @@ // // RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \ // RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \ +// RUN: --target=x86_64-unknown-linux-gnux32 \ +// RUN: | FileCheck --check-prefix=CHECK-X32 %s +// CHECK-X32: "-cc1" "-triple" "x86_64-unknown-linux-gnux32" +// CHECK-X32: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\}}as" "--x32" +// CHECK-X32: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\}}ld" {{.*}} "-m" "elf32_x86_64" +// +// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \ +// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \ // RUN: --target=x86_64-unknown-linux-gnu -m32 \ // RUN: | FileCheck --check-prefix=CHECK-I386 %s // Index: test/Driver/dyld-prefix.c =================================================================== --- test/Driver/dyld-prefix.c +++ test/Driver/dyld-prefix.c @@ -7,3 +7,6 @@ // RUN: %clang -target x86_64-unknown-linux --dyld-prefix /foo -### %t.o 2>&1 | FileCheck --check-prefix=CHECK-64 %s // CHECK-64: "-dynamic-linker" "/foo/lib64/ld-linux-x86-64.so.2" + +// RUN: %clang -target x86_64-unknown-linux-gnux32 --dyld-prefix /foo -### %t.o 2>&1 | FileCheck --check-prefix=CHECK-X32 %s +// CHECK-X32: "-dynamic-linker" "/foo/libx32/ld-linux-x32.so.2" Index: test/Driver/linux-header-search.cpp =================================================================== --- test/Driver/linux-header-search.cpp +++ test/Driver/linux-header-search.cpp @@ -55,6 +55,22 @@ // CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include" // // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ +// RUN: -target x86_64-unknown-linux-gnux32 \ +// RUN: --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree \ +// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-14-04 %s +// CHECK-UBUNTU-14-04: "{{[^"]*}}clang{{[^"]*}}" "-cc1" +// CHECK-UBUNTU-14-04: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-UBUNTU-14-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8" +// CHECK-UBUNTU-14-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/x86_64-linux-gnu/x32" +// CHECK-UBUNTU-14-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/backward" +// CHECK-UBUNTU-14-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/x86_64-linux-gnu/c++/4.8/x32" +// CHECK-UBUNTU-14-04: "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK-UBUNTU-14-04: "-internal-isystem" "{{.*}}{{/|\\\\}}lib{{(64|x32)?}}{{/|\\\\}}clang{{/|\\\\}}{{[0-9]\.[0-9]\.[0-9]}}{{/|\\\\}}include" +// CHECK-UBUNTU-14-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/x86_64-linux-gnu" +// CHECK-UBUNTU-14-04: "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-UBUNTU-14-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +/// +// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ // RUN: -target arm-linux-gnueabihf \ // RUN: --sysroot=%S/Inputs/ubuntu_13.04_multiarch_tree \ // RUN: | FileCheck --check-prefix=CHECK-UBUNTU-13-04-CROSS %s Index: test/Driver/linux-ld.c =================================================================== --- test/Driver/linux-ld.c +++ test/Driver/linux-ld.c @@ -34,6 +34,19 @@ // CHECK-LD-64: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" // // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: --target=x86_64-unknown-linux-gnux32 \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-LD-X32 %s +// CHECK-LD-X32-NOT: warning: +// CHECK-LD-X32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-LD-X32: "--eh-frame-hdr" +// CHECK-LD-X32: "-m" "elf32_x86_64" +// CHECK-LD-X32: "-dynamic-linker" +// CHECK-LD-X32: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" +// CHECK-LD-X32: "-lc" +// CHECK-LD-X32: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" +// +// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: --target=x86_64-unknown-linux \ // RUN: --sysroot=%S/Inputs/basic_linux_tree \ // RUN: --rtlib=compiler-rt \ @@ -186,6 +199,23 @@ // CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib" // // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: --target=x86_64-unknown-linux-gnux32 \ +// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-X32 %s +// CHECK-X32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-X32: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/x32{{/|\\\\}}crtbegin.o" +// CHECK-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/x32" +// CHECK-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib/../libx32" +// CHECK-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../libx32" +// CHECK-X32: "-L[[SYSROOT]]/lib/../libx32" +// CHECK-X32: "-L[[SYSROOT]]/usr/lib/../libx32" +// CHECK-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0" +// CHECK-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib" +// CHECK-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.." +// CHECK-X32: "-L[[SYSROOT]]/lib" +// CHECK-X32: "-L[[SYSROOT]]/usr/lib" +// +// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: --target=x86_64-unknown-linux -m32 \ // RUN: --gcc-toolchain=%S/Inputs/multilib_64bit_linux_tree/usr \ // RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \ @@ -364,6 +394,26 @@ // CHECK-UBUNTU-14-04-PPC64LE: "{{.*}}/usr/lib/gcc/powerpc64le-linux-gnu/4.8{{/|\\\\}}crtend.o" // CHECK-UBUNTU-14-04-PPC64LE: "{{.*}}/usr/lib/gcc/powerpc64le-linux-gnu/4.8/../../../powerpc64le-linux-gnu{{/|\\\\}}crtn.o" // +// Check Ubuntu 14.04 on x32. +// "/usr/lib/gcc/x86_64-linux-gnu/4.8/x32/crtend.o" "/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../libx32/crtn.o" +// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: --target=x86_64-unknown-linux-gnux32 \ +// RUN: --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree \ +// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-14-04-X32 %s +// CHECK-UBUNTU-14-04-X32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-UBUNTU-14-04-X32: "{{.*}}/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../libx32{{/|\\\\}}crt1.o" +// CHECK-UBUNTU-14-04-X32: "{{.*}}/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../libx32{{/|\\\\}}crti.o" +// CHECK-UBUNTU-14-04-X32: "{{.*}}/usr/lib/gcc/x86_64-linux-gnu/4.8/x32{{/|\\\\}}crtbegin.o" +// CHECK-UBUNTU-14-04-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.8/x32" +// CHECK-UBUNTU-14-04-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../libx32" +// CHECK-UBUNTU-14-04-X32: "-L[[SYSROOT]]/lib/../libx32" +// CHECK-UBUNTU-14-04-X32: "-L[[SYSROOT]]/usr/lib/../libx32" +// CHECK-UBUNTU-14-04-X32: "-L[[SYSROOT]]/usr/lib/x86_64-linux-gnu/../../libx32" +// CHECK-UBUNTU-14-04-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.8" +// CHECK-UBUNTU-14-04-X32: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.8/../../.." +// CHECK-UBUNTU-14-04-X32: "{{.*}}/usr/lib/gcc/x86_64-linux-gnu/4.8/x32{{/|\\\\}}crtend.o" +// CHECK-UBUNTU-14-04-X32: "{{.*}}/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../libx32{{/|\\\\}}crtn.o" +// // Check fedora 18 on arm. // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: --target=armv7-unknown-linux-gnueabihf \