Steven Newbury
2013-Aug-22 06:04 UTC
[LLVMdev] [RFC PATCH] X32 ABI support for Clang/compiler-rt
Hi, I'm working on bringing up complete coverage for a Gentoo x32 "desktop" system. I've been cooking up quite a few patches for various packages to push upstream, but right now, the biggest blocker is the lack of support for building with/codegen targeting x32 in llvm/clang. Since the x32 patches were sent last year, I see support code has landed in LLVM, and basic handling of 32-bit pointers in Clang, but no elf32_x86_64 codegen or support for the -mx32 switch. I've been trying to get x32 ABI support working in Clang and compiler-rt, I based off the previous clang patch, bringing it up to date with the changes in trunk, and hacked together handling of x32 "ARCH" support for compiler-rt. (there must be a better way??) Unfortunately, although the build succeeds as far as beginning to build compiler-rt the resulting clang doesn't seem to respect the fact that the target is x86_64-pc-linux-gnux32, nor that the "-mx32" opt has been supplied. Something is clearly missing. Can somebody please take a look at the patches, and look to see what I'm missing/where I've gone wrong, or otherwise point me to a working patchset/repo if I'm duplicating effort. Patches to follow...
Steven Newbury
2013-Aug-22 06:07 UTC
[LLVMdev] [RFC PATCH] X32 ABI support for Clang/compiler-rt (Clang patch)
Clang patch for X32 support. Applies against current trunk. --- ./tools/clang/include/clang/Driver/Options.td.orig 2013-05-16 21:51:51.286129820 +0000 +++ ./tools/clang/include/clang/Driver/Options.td 2013-05-16 21:53:24.875004239 +0000 @@ -841,6 +841,7 @@ HelpText<"Enable hexagon-qdsp6 backward compatibility">; def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>; def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>; +def mx32 : Flag<["-"], "mx32">, Group<m_Group>, Flags<[DriverOption]>; def m64 : Flag<["-"], "m64">, Group<m_Group>, Flags<[DriverOption]>; def mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>; def march_EQ : Joined<["-"], "march=">, Group<m_Group>; --- ./tools/clang/lib/Driver/Driver.cpp.orig +++ ./tools/clang/lib/Driver/Driver.cpp @@ -1700,6 +1700,9 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, if (Target.getArch() == llvm::Triple::ppc) Target.setArch(llvm::Triple::ppc64); } + } else if (Args.getLastArg(options::OPT_mx32)) { + if (Target.getArch() == llvm::Triple::x86_64) + Target.setEnvironment(llvm::Triple::GNUX32); } return Target; --- ./tools/clang/lib/Basic/Targets.cpp.orig 2013-08-18 12:00:04.501402572 +0000 +++ ./tools/clang/lib/Basic/Targets.cpp 2013-08-18 12:08:11.086175660 +0000 @@ -2384,6 +2384,14 @@ Builder.defineMacro("__amd64"); Builder.defineMacro("__x86_64"); Builder.defineMacro("__x86_64__"); + if (PointerWidth == 64 && getLongWidth() == 64) { + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + } else if (PointerWidth == 32 && getLongWidth() == 32 && + getIntWidth() == 32) { + Builder.defineMacro("_ILP32"); + Builder.defineMacro("__ILP32__"); + } } else { DefineStd(Builder, "i386", Opts); } @@ -3013,20 +3021,31 @@ 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; + if (IsX32) { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + } else { + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + Int64Type = SignedLong; + } RegParmMax = 6; - DescriptionString "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"; + DescriptionString = IsX32 ? + "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" : + "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"; // Use fpret only for long double. RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); --- ./tools/clang/lib/Driver/ToolChains.h.orig 2013-08-18 13:38:36.158022094 +0000 +++ ./tools/clang/lib/Driver/ToolChains.h 2013-08-18 13:39:12.822210498 +0000 @@ -121,7 +121,7 @@ SmallVectorImpl<StringRef> &BiarchLibDirs, SmallVectorImpl<StringRef> &BiarchTripleAliases); - void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch, + void ScanLibDirForGCCTriple(llvm::Triple TargetTriple, const llvm::opt::ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, --- ./tools/clang/lib/Driver/Tools.cpp.orig 2013-08-18 13:35:35.783789840 +0000 +++ ./tools/clang/lib/Driver/Tools.cpp 2013-08-18 13:42:18.806549941 +0000 @@ -6045,6 +6045,8 @@ ToolChain.getArch() == llvm::Triple::ppc64le || ToolChain.getArch() == llvm::Triple::systemz) return "/lib64/ld64.so.1"; + else if (ToolChain.getTriple().getEnvironment() =llvm::Triple::GNUX32) + return "/libx32/ld-linux-x32.so.2"; else return "/lib64/ld-linux-x86-64.so.2"; } @@ -6125,8 +6127,12 @@ } else if (ToolChain.getArch() == llvm::Triple::systemz) CmdArgs.push_back("elf64_s390"); - else - CmdArgs.push_back("elf_x86_64"); + else if (ToolChain.getArch() == llvm::Triple::x86_64) + CmdArgs.push_back(ToolChain.getTriple().getEnvironment() =+ llvm::Triple::GNUX32 + ? "elf32_x86_64" : "elf_x86_64"); + else + llvm_unreachable("unknown arch"); if (Args.hasArg(options::OPT_static)) { if (ToolChain.getArch() == llvm::Triple::arm --- ./tools/clang/lib/Driver/ToolChains.cpp.orig 2013-08-18 14:18:42.527568969 +0000 +++ ./tools/clang/lib/Driver/ToolChains.cpp 2013-08-18 14:20:41.647025183 +0000 @@ -998,7 +998,6 @@ llvm::Triple BiarchVariantTriple TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); - llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // The library directories which may contain GCC installations. SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs; // The compatible GCC triples for this particular architecture. @@ -1035,7 +1034,7 @@ if (!llvm::sys::fs::exists(LibDir)) continue; for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k) - ScanLibDirForGCCTriple(TargetArch, Args, LibDir, + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, CandidateTripleAliases[k]); } for (unsigned j = 0, je = CandidateBiarchLibDirs.size(); j < je; ++j) { @@ -1044,7 +1043,7 @@ continue; for (unsigned k = 0, ke = CandidateBiarchTripleAliases.size(); k < ke; ++k) - ScanLibDirForGCCTriple(TargetArch, Args, LibDir, + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, CandidateBiarchTripleAliases[k], /*NeedsBiarchSuffix=*/ true); } @@ -1321,6 +1351,7 @@ } static bool findTargetBiarchSuffix(std::string &Suffix, StringRef Path, + llvm::Triple TargetTriple, llvm::Triple::ArchType TargetArch, const ArgList &Args) { // FIXME: This routine was only intended to model bi-arch toolchains which @@ -1351,6 +1382,8 @@ TargetArch == llvm::Triple::ppc64 || TargetArch == llvm::Triple::systemz) Suffix = "/64"; + else if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) + Suffix = "/x32"; else Suffix = "/32"; @@ -1358,9 +1391,10 @@ } void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( - llvm::Triple::ArchType TargetArch, const ArgList &Args, + llvm::Triple TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix) { + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // There are various different suffixes involving the triple we // check for. We also record what is necessary to walk from each back // up to the lib directory. @@ -1413,7 +1447,7 @@ // crtbegin.o without the subdirectory. std::string BiarchSuffix; - if (findTargetBiarchSuffix(BiarchSuffix, LI->path(), TargetArch, Args)) { + if (findTargetBiarchSuffix(BiarchSuffix, LI->path(), TargetTriple, TargetArch, Args)) { GCCBiarchSuffix = BiarchSuffix; } else { if (NeedsBiarchSuffix || @@ -2186,8 +2220,9 @@ static StringRef getMultilibDir(const llvm::Triple &Triple, const ArgList &Args) { + const bool IsX32 = Triple.getEnvironment() == llvm::Triple::GNUX32; if (!isMipsArch(Triple.getArch())) - return Triple.isArch32Bit() ? "lib32" : "lib64"; + return Triple.isArch32Bit() ? "lib32" : IsX32 ? "libx32" : "lib64"; // lib32 directory has a special meaning on MIPS targets. // It contains N32 ABI binaries. Use this folder if produce --- ./lib/Target/X86/X86JITInfo.cpp.orig 2013-08-19 11:38:44.998820677 +0000 +++ ./lib/Target/X86/X86JITInfo.cpp 2013-08-19 11:39:14.769549714 +0000 @@ -396,6 +396,7 @@ // PC-relative branch instead of loading the actual address. (This is // considerably shorter than the 64-bit immediate load already there.) // We assume here intptr_t is 64 bits. +#if defined (__LP64__) intptr_t diff = NewVal-RetAddr+7; if (diff >= -2147483648LL && diff <= 2147483647LL) { *(unsigned char*)(RetAddr-0xc) = 0xE9; @@ -405,6 +406,11 @@ ((unsigned char*)RetAddr)[0] = (2 | (4 << 3) | (3 << 6)); } sys::ValgrindDiscardTranslations((void*)(RetAddr-0xc), 0xd); +#else // If intptr_t is only 32 bits, always use a PC-relative branch. + *(unsigned char*)(RetAddr-0xc) = 0xE9; + *(intptr_t *)(RetAddr-0xb) = NewVal-RetAddr+7; + sys::ValgrindDiscardTranslations((void*)(RetAddr-0xc), 0xd); +#endif #else ((unsigned char*)RetAddr)[-1] = 0xE9; sys::ValgrindDiscardTranslations((void*)(RetAddr-1), 5); @@ -442,7 +448,7 @@ void *X86JITInfo::emitGlobalValueIndirectSym(const GlobalValue* GV, void *ptr, JITCodeEmitter &JCE) { -#if defined (X86_64_JIT) +#if defined (X86_64_JIT) && defined (__LP64__) const unsigned Alignment = 8; uint8_t Buffer[8]; uint8_t *Cur = Buffer; @@ -481,7 +487,7 @@ JCE.emitAlignment(4); void *Result = (void*)JCE.getCurrentPCValue(); if (NotCC) { -#if defined (X86_64_JIT) +#if defined (X86_64_JIT) && defined (__LP64__) JCE.emitByte(0x49); // REX prefix JCE.emitByte(0xB8+2); // movabsq r10 JCE.emitWordLE((unsigned)(intptr_t)Target); @@ -496,7 +502,7 @@ return Result; } -#if defined (X86_64_JIT) +#if defined (X86_64_JIT) && defined (__LP64__) JCE.emitByte(0x49); // REX prefix JCE.emitByte(0xB8+2); // movabsq r10 JCE.emitWordLE((unsigned)(intptr_t)Target);
Steven Newbury
2013-Aug-22 06:09 UTC
[LLVMdev] [RFC PATCH] X32 ABI support for Clang/compiler-rt (compiler-rt patch)
X32 support patch for compiler-rt. Applies against current trunk. --- projects/compiler-rt/make/platform/clang_linux.mk~ 2013-08-21 06:27:38.000000000 +0000 +++ projects/compiler-rt/make/platform/clang_linux.mk 2013-08-21 11:16:55.891621025 +0000 @@ -41,7 +41,18 @@ SupportedArches += x86_64 endif else - SupportedArches := x86_64 + # x86-64 arch has two ABIs 64 bit x86-64 and 32 bit x32 + ifeq ($(lastword $(subst -gnu, ,$(CompilerTargetTriple))),x32) + SupportedArches := x32 + ifeq ($(call TryCompile,$(CC),$(test_source),-m64),0) + SupportedArches += x86_64 + endif + else + SupportedArches := x86_64 + ifeq ($(call TryCompile,$(CC),$(test_source),-mx32),0) + SupportedArches += x32 + endif + endif ifeq ($(call TryCompile,$(CC),$(test_source),-m32),0) SupportedArches += i386 endif @@ -74,6 +85,22 @@ Arch.lsan-x86_64 := x86_64 endif +# Build runtime libraries for x32. +ifeq ($(call contains,$(SupportedArches),x32),true) +Configs += full-x32 profile-x32 san-x32 asan-x32 tsan-x32 \ + msan-x32 ubsan-x32 ubsan_cxx-x32 dfsan-x32 lsan-x32 +Arch.full-x32 := x32 +Arch.profile-x32 := x32 +Arch.san-x32 := x32 +Arch.asan-x32 := x32 +Arch.tsan-x32 := x32 +Arch.msan-x32 := x32 +Arch.ubsan-x32 := x32 +Arch.ubsan_cxx-x32 := x32 +Arch.dfsan-x32 := x32 +Arch.lsan-x32 := x32 +endif + ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),) Configs += asan-arm-android Arch.asan-arm-android := arm-android @@ -89,22 +116,33 @@ CFLAGS.full-i386 := $(CFLAGS) -m32 CFLAGS.full-x86_64 := $(CFLAGS) -m64 +CFLAGS.full-x32 := $(CFLAGS) -mx32 CFLAGS.profile-i386 := $(CFLAGS) -m32 CFLAGS.profile-x86_64 := $(CFLAGS) -m64 +CFLAGS.profile-x32 := $(CFLAGS) -mx32 CFLAGS.san-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) -fno-rtti CFLAGS.san-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti +CFLAGS.san-x32 := $(CFLAGS) -mx32 $(SANITIZER_CFLAGS) -fno-rtti CFLAGS.asan-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) -fno-rtti \ -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1 CFLAGS.asan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti \ -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1 +CFLAGS.asan-x32 := $(CFLAGS) -mx32 $(SANITIZER_CFLAGS) -fno-rtti \ + -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1 CFLAGS.tsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti +CFLAGS.tsan-x32 := $(CFLAGS) -mx32 $(SANITIZER_CFLAGS) -fno-rtti CFLAGS.msan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti +CFLAGS.msan-x32 := $(CFLAGS) -mx32 $(SANITIZER_CFLAGS) -fno-rtti CFLAGS.ubsan-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) -fno-rtti CFLAGS.ubsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti +CFLAGS.ubsan-x32 := $(CFLAGS) -mx32 $(SANITIZER_CFLAGS) -fno-rtti CFLAGS.ubsan_cxx-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) CFLAGS.ubsan_cxx-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) +CFLAGS.ubsan_cxx-x32 := $(CFLAGS) -mx32 $(SANITIZER_CFLAGS) CFLAGS.dfsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) +CFLAGS.dfsan-x32 := $(CFLAGS) -mx32 $(SANITIZER_CFLAGS) CFLAGS.lsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) +CFLAGS.lsan-x32 := $(CFLAGS) -mx32 $(SANITIZER_CFLAGS) SHARED_LIBRARY.asan-arm-android := 1 ANDROID_COMMON_FLAGS := -target arm-linux-androideabi \ @@ -120,30 +158,45 @@ # enough support to build the sanitizers or profile runtimes. CFLAGS.full-i386 += --sysroot=$(ProjSrcRoot)/SDKs/linux CFLAGS.full-x86_64 += --sysroot=$(ProjSrcRoot)/SDKs/linux +CFLAGS.full-x32 += --sysroot=$(ProjSrcRoot)/SDKs/linux FUNCTIONS.full-i386 := $(CommonFunctions) $(ArchFunctions.i386) FUNCTIONS.full-x86_64 := $(CommonFunctions) $(ArchFunctions.x86_64) +FUNCTIONS.full-x32 := $(CommonFunctions) $(ArchFunctions.x32) FUNCTIONS.profile-i386 := GCDAProfiling FUNCTIONS.profile-x86_64 := GCDAProfiling +FUNCTIONS.profile-x32 := GCDAProfiling FUNCTIONS.san-i386 := $(SanitizerCommonFunctions) FUNCTIONS.san-x86_64 := $(SanitizerCommonFunctions) +FUNCTIONS.san-x32 := $(SanitizerCommonFunctions) FUNCTIONS.asan-i386 := $(AsanFunctions) $(InterceptionFunctions) \ $(SanitizerCommonFunctions) FUNCTIONS.asan-x86_64 := $(AsanFunctions) $(InterceptionFunctions) \ $(SanitizerCommonFunctions) $(LsanCommonFunctions) +FUNCTIONS.asan-x32 := $(AsanFunctions) $(InterceptionFunctions) \ + $(SanitizerCommonFunctions) $(LsanCommonFunctions) FUNCTIONS.asan-arm-android := $(AsanFunctions) $(InterceptionFunctions) \ $(SanitizerCommonFunctions) FUNCTIONS.tsan-x86_64 := $(TsanFunctions) $(InterceptionFunctions) \ $(SanitizerCommonFunctions) +FUNCTIONS.tsan-x32 := $(TsanFunctions) $(InterceptionFunctions) \ + $(SanitizerCommonFunctions) FUNCTIONS.msan-x86_64 := $(MsanFunctions) $(InterceptionFunctions) \ $(SanitizerCommonFunctions) +FUNCTIONS.msan-x32 := $(MsanFunctions) $(InterceptionFunctions) \ + $(SanitizerCommonFunctions) FUNCTIONS.ubsan-i386 := $(UbsanFunctions) FUNCTIONS.ubsan-x86_64 := $(UbsanFunctions) +FUNCTIONS.ubsan-x32 := $(UbsanFunctions) FUNCTIONS.ubsan_cxx-i386 := $(UbsanCXXFunctions) FUNCTIONS.ubsan_cxx-x86_64 := $(UbsanCXXFunctions) +FUNCTIONS.ubsan_cxx-x32 := $(UbsanCXXFunctions) FUNCTIONS.dfsan-x86_64 := $(DfsanFunctions) $(SanitizerCommonFunctions) +FUNCTIONS.dfsan-x32 := $(DfsanFunctions) $(SanitizerCommonFunctions) FUNCTIONS.lsan-x86_64 := $(LsanFunctions) $(InterceptionFunctions) \ $(SanitizerCommonFunctions) +FUNCTIONS.lsan-x32 := $(LsanFunctions) $(InterceptionFunctions) \ + $(SanitizerCommonFunctions) # Always use optimized variants. OPTIMIZED := 1 --- tools/clang/runtime/compiler-rt/Makefile.orig 2013-08-21 16:20:43.915932247 +0000 +++ tools/clang/runtime/compiler-rt/Makefile 2013-08-21 17:03:15.856154519 +0000 @@ -96,29 +96,66 @@ $(1) $$cflags $(2) -o /dev/null > /dev/null 2> /dev/null ; \ echo $$?) -# We try to build 32-bit runtimes both on 32-bit hosts and 64-bit hosts. -Runtime32BitConfigs = \ +# We try to build x86 runtimes both on x86 hosts and 64-bit hosts. +Runtimex86Configs = \ full-i386.a profile-i386.a san-i386.a asan-i386.a ubsan-i386.a \ ubsan_cxx-i386.a +Runtime64BitConfigs = \ + full-x86_64.a profile-x86_64.a san-x86_64.a asan-x86_64.a \ + tsan-x86_64.a msan-x86_64.a ubsan-x86_64.a ubsan_cxx-x86_64.a \ + dfsan-x86_64.a lsan-x86_64.a + +Runtimex32Configs += \ + full-x32.a profile-x32.a san-x32.a asan-x32.a \ + tsan-x32.a msan-x32.a ubsan-x32.a ubsan_cxx-x32.a \ + dfsan-x32.a lsan-x32.a + + # We currently only try to generate runtime libraries on x86. ifeq ($(ARCH),x86) -RuntimeLibrary.linux.Configs += $(Runtime32BitConfigs) +RuntimeLibrary.linux.Configs += $(Runtimex86Configs) + +ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),) +RuntimeLibrary.linux.Configs += asan-arm-android.so +endif endif ifeq ($(ARCH),x86_64) -RuntimeLibrary.linux.Configs += \ - full-x86_64.a profile-x86_64.a san-x86_64.a asan-x86_64.a \ - tsan-x86_64.a msan-x86_64.a ubsan-x86_64.a ubsan_cxx-x86_64.a \ - dfsan-x86_64.a lsan-x86_64.a -# We need to build 32-bit ASan/UBsan libraries on 64-bit platform, and add them +CompilerTargetTriple := $(shell \ + $(CC) -v 2>&1 | grep 'Target:' | cut -d' ' -f2) +ifeq ($(CompilerTargetTriple),) +$(error "unable to infer compiler target triple for $(CC)") +endif +ifeq ($(lastword $(subst -gnu, ,$(CompilerTargetTriple))),x32) +ARCH=x32 +RuntimeLibrary.linux.Configs += $(Runtimex32Configs) +# We need to build x86 ASan/UBsan libraries on x32 platform, and add them # to the list of runtime libraries to make -# "clang -fsanitize=(address|undefined) -m32" work. -# We check that Clang can produce working 32-bit binaries by compiling a simple +# "clang -fsanitize=(address|undefined) -m32/-m64" work. +# We check that Clang can produce working 32/64-bit binaries by compiling a simple # executable. test_source $(LLVM_SRC_ROOT)/tools/clang/runtime/compiler-rt/clang_linux_test_input.c +ifeq ($(call TryCompile,$(ToolDir)/clang,$(test_source),-m64),0) +RuntimeLibrary.linux.Configs += $(Runtime64BitConfigs) +endif ifeq ($(call TryCompile,$(ToolDir)/clang,$(test_source),-m32),0) -RuntimeLibrary.linux.Configs += $(Runtime32BitConfigs) +RuntimeLibrary.linux.Configs += $(Runtimex86Configs) +endif +else +RuntimeLibrary.linux.Configs += $(Runtime64BitConfigs) +# We need to build x86/x32 ASan/UBsan libraries on 64-bit platform, and add them +# to the list of runtime libraries to make +# "clang -fsanitize=(address|undefined) -m32/-mx32" work. +# We check that Clang can produce working x86 binaries by compiling a simple +# executable. +test_source $(LLVM_SRC_ROOT)/tools/clang/runtime/compiler-rt/clang_linux_test_input.c +ifeq ($(call TryCompile,$(ToolDir)/clang,$(test_source),-m32),0) +RuntimeLibrary.linux.Configs += $(Runtimex86Configs) +endif +ifeq ($(call TryCompile,$(ToolDir)/clang,$(test_source),-mx32),0) +RuntimeLibrary.linux.Configs += $(Runtimex32Configs) +endif endif ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),) RuntimeLibrary.linux.Configs += asan-arm-android.so
Dmitri Gribenko
2013-Aug-22 06:54 UTC
[LLVMdev] [RFC PATCH] X32 ABI support for Clang/compiler-rt (Clang patch)
On Wed, Aug 21, 2013 at 11:07 PM, Steven Newbury <steve at snewbury.org.uk> wrote:> Clang patch for X32 support. Applies against current trunk.Not a real review, but it seems like this change needs tests -- at least driver tests, and tests for predefined macros. Dmitri -- main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if (j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com>*/
Dmitri Gribenko
2013-Aug-22 06:59 UTC
[LLVMdev] [RFC PATCH] X32 ABI support for Clang/compiler-rt
On Wed, Aug 21, 2013 at 11:04 PM, Steven Newbury <steve at snewbury.org.uk> wrote:> I've been trying > to get x32 ABI support working in Clang and compiler-rt, I based off the > previous clang patch, bringing it up to date with the changes in trunk, > and hacked together handling of x32 "ARCH" support for compiler-rt. > (there must be a better way??)If you are just trying to get basic things working, you don't need to port compiler-rt immediately. It is still pretty important (for example, to support features like Address Sanitizer), but not critical -- you will still get a useable Clang without building compiler-rt. Dmitri -- main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if (j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com>*/
Steven Newbury
2013-Aug-22 07:23 UTC
[LLVMdev] [RFC PATCH] X32 ABI support for Clang/compiler-rt
On Wed, 2013-08-21 at 23:59 -0700, Dmitri Gribenko wrote:> On Wed, Aug 21, 2013 at 11:04 PM, Steven Newbury <steve at snewbury.org.uk> wrote: > > I've been trying > > to get x32 ABI support working in Clang and compiler-rt, I based off the > > previous clang patch, bringing it up to date with the changes in trunk, > > and hacked together handling of x32 "ARCH" support for compiler-rt. > > (there must be a better way??) > > If you are just trying to get basic things working, you don't need to > port compiler-rt immediately. It is still pretty important (for > example, to support features like Address Sanitizer), but not critical > -- you will still get a useable Clang without building compiler-rt. > > Dmitri >Having Clang working would of course be my primary goal, that said, being able to compile compiler-rt is a pretty good test all is working as it should be! :) It's also built/installed as part of the Gentoo llvm ebuild when the clang useflag is enabled, so from that point of view, I need to get it working.
Alexey Samsonov
2013-Aug-22 07:29 UTC
[LLVMdev] [cfe-dev] [RFC PATCH] X32 ABI support for Clang/compiler-rt
Ah, I've replied in a different thread already. What Dmitri says - If you're interesting in only building the Clang on x32 host, you may avoid checking out compiler-rt repo for now. On Thu, Aug 22, 2013 at 10:59 AM, Dmitri Gribenko <gribozavr at gmail.com>wrote:> On Wed, Aug 21, 2013 at 11:04 PM, Steven Newbury <steve at snewbury.org.uk> > wrote: > > I've been trying > > to get x32 ABI support working in Clang and compiler-rt, I based off the > > previous clang patch, bringing it up to date with the changes in trunk, > > and hacked together handling of x32 "ARCH" support for compiler-rt. > > (there must be a better way??) > > If you are just trying to get basic things working, you don't need to > port compiler-rt immediately. It is still pretty important (for > example, to support features like Address Sanitizer), but not critical > -- you will still get a useable Clang without building compiler-rt. > > Dmitri > > -- > main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if > (j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com>*/ > _______________________________________________ > cfe-dev mailing list > cfe-dev at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev >-- Alexey Samsonov, MSK -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20130822/114063e2/attachment.html>
Steven Newbury
2013-Aug-22 14:22 UTC
[LLVMdev] [NEW PATCH] X32 ABI support for Clang/compiler-rt (Clang patch)
This patch is still not creating elf32_x86_64 objects. No idea why. :( It does however, fix elf_x86_64 (-m64) code generation on x32 hosts which is nice. :) --- ./tools/clang/include/clang/Driver/Options.td.orig 2013-05-16 21:51:51.286129820 +0000 +++ ./tools/clang/include/clang/Driver/Options.td 2013-05-16 21:53:24.875004239 +0000 @@ -841,6 +841,7 @@ HelpText<"Enable hexagon-qdsp6 backward compatibility">; def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>; def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>; +def mx32 : Flag<["-"], "mx32">, Group<m_Group>, Flags<[DriverOption]>; def m64 : Flag<["-"], "m64">, Group<m_Group>, Flags<[DriverOption]>; def mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>; def march_EQ : Joined<["-"], "march=">, Group<m_Group>; --- ./tools/clang/lib/Basic/Targets.cpp.orig 2013-08-18 12:00:04.501402572 +0000 +++ ./tools/clang/lib/Basic/Targets.cpp 2013-08-18 12:08:11.086175660 +0000 @@ -2384,6 +2384,14 @@ Builder.defineMacro("__amd64"); Builder.defineMacro("__x86_64"); Builder.defineMacro("__x86_64__"); + if (PointerWidth == 64 && getLongWidth() == 64) { + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + } else if (PointerWidth == 32 && getLongWidth() == 32 && + getIntWidth() == 32) { + Builder.defineMacro("_ILP32"); + Builder.defineMacro("__ILP32__"); + } } else { DefineStd(Builder, "i386", Opts); } @@ -3013,20 +3021,31 @@ 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; + if (IsX32) { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + } else { + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + Int64Type = SignedLong; + } RegParmMax = 6; - DescriptionString "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"; + DescriptionString = IsX32 ? + "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" : + "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"; // Use fpret only for long double. RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); --- ./tools/clang/lib/Driver/ToolChains.h.orig 2013-08-18 13:38:36.158022094 +0000 +++ ./tools/clang/lib/Driver/ToolChains.h 2013-08-18 13:39:12.822210498 +0000 @@ -121,7 +121,7 @@ SmallVectorImpl<StringRef> &BiarchLibDirs, SmallVectorImpl<StringRef> &BiarchTripleAliases); - void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch, + void ScanLibDirForGCCTriple(llvm::Triple TargetTriple, const llvm::opt::ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, --- ./tools/clang/lib/Driver/Tools.cpp.orig 2013-08-18 13:35:35.783789840 +0000 +++ ./tools/clang/lib/Driver/Tools.cpp 2013-08-18 13:42:18.806549941 +0000 @@ -6045,6 +6045,8 @@ ToolChain.getArch() == llvm::Triple::ppc64le || ToolChain.getArch() == llvm::Triple::systemz) return "/lib64/ld64.so.1"; + else if (ToolChain.getTriple().getEnvironment() =llvm::Triple::GNUX32) + return "/libx32/ld-linux-x32.so.2"; else return "/lib64/ld-linux-x86-64.so.2"; } @@ -6125,8 +6127,12 @@ } else if (ToolChain.getArch() == llvm::Triple::systemz) CmdArgs.push_back("elf64_s390"); - else - CmdArgs.push_back("elf_x86_64"); + else if (ToolChain.getArch() == llvm::Triple::x86_64) + CmdArgs.push_back(ToolChain.getTriple().getEnvironment() =+ llvm::Triple::GNUX32 + ? "elf32_x86_64" : "elf_x86_64"); + else + llvm_unreachable("unknown arch"); if (Args.hasArg(options::OPT_static)) { if (ToolChain.getArch() == llvm::Triple::arm --- ./tools/clang/lib/Driver/ToolChains.cpp.orig 2013-08-18 14:18:42.527568969 +0000 +++ ./tools/clang/lib/Driver/ToolChains.cpp 2013-08-18 14:20:41.647025183 +0000 @@ -998,7 +998,6 @@ llvm::Triple BiarchVariantTriple TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); - llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // The library directories which may contain GCC installations. SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs; // The compatible GCC triples for this particular architecture. @@ -1035,7 +1034,7 @@ if (!llvm::sys::fs::exists(LibDir)) continue; for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k) - ScanLibDirForGCCTriple(TargetArch, Args, LibDir, + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, CandidateTripleAliases[k]); } for (unsigned j = 0, je = CandidateBiarchLibDirs.size(); j < je; ++j) { @@ -1044,7 +1043,7 @@ continue; for (unsigned k = 0, ke = CandidateBiarchTripleAliases.size(); k < ke; ++k) - ScanLibDirForGCCTriple(TargetArch, Args, LibDir, + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, CandidateBiarchTripleAliases[k], /*NeedsBiarchSuffix=*/ true); } @@ -1321,6 +1351,7 @@ } static bool findTargetBiarchSuffix(std::string &Suffix, StringRef Path, + llvm::Triple TargetTriple, llvm::Triple::ArchType TargetArch, const ArgList &Args) { // FIXME: This routine was only intended to model bi-arch toolchains which @@ -1351,6 +1382,8 @@ TargetArch == llvm::Triple::ppc64 || TargetArch == llvm::Triple::systemz) Suffix = "/64"; + else if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) + Suffix = "/x32"; else Suffix = "/32"; @@ -1358,9 +1391,10 @@ } void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( - llvm::Triple::ArchType TargetArch, const ArgList &Args, + llvm::Triple TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix) { + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // There are various different suffixes involving the triple we // check for. We also record what is necessary to walk from each back // up to the lib directory. @@ -1413,7 +1447,7 @@ // crtbegin.o without the subdirectory. std::string BiarchSuffix; - if (findTargetBiarchSuffix(BiarchSuffix, LI->path(), TargetArch, Args)) { + if (findTargetBiarchSuffix(BiarchSuffix, LI->path(), TargetTriple, TargetArch, Args)) { GCCBiarchSuffix = BiarchSuffix; } else { if (NeedsBiarchSuffix || @@ -2186,8 +2220,9 @@ static StringRef getMultilibDir(const llvm::Triple &Triple, const ArgList &Args) { + const bool IsX32 = Triple.getEnvironment() == llvm::Triple::GNUX32; if (!isMipsArch(Triple.getArch())) - return Triple.isArch32Bit() ? "lib32" : "lib64"; + return Triple.isArch32Bit() ? "lib32" : IsX32 ? "libx32" : "lib64"; // lib32 directory has a special meaning on MIPS targets. // It contains N32 ABI binaries. Use this folder if produce --- ./lib/Target/X86/X86JITInfo.cpp.orig 2013-08-19 11:38:44.998820677 +0000 +++ ./lib/Target/X86/X86JITInfo.cpp 2013-08-19 11:39:14.769549714 +0000 @@ -396,6 +396,7 @@ // PC-relative branch instead of loading the actual address. (This is // considerably shorter than the 64-bit immediate load already there.) // We assume here intptr_t is 64 bits. +#if defined (__LP64__) intptr_t diff = NewVal-RetAddr+7; if (diff >= -2147483648LL && diff <= 2147483647LL) { *(unsigned char*)(RetAddr-0xc) = 0xE9; @@ -405,6 +406,11 @@ ((unsigned char*)RetAddr)[0] = (2 | (4 << 3) | (3 << 6)); } sys::ValgrindDiscardTranslations((void*)(RetAddr-0xc), 0xd); +#else // If intptr_t is only 32 bits, always use a PC-relative branch. + *(unsigned char*)(RetAddr-0xc) = 0xE9; + *(intptr_t *)(RetAddr-0xb) = NewVal-RetAddr+7; + sys::ValgrindDiscardTranslations((void*)(RetAddr-0xc), 0xd); +#endif #else ((unsigned char*)RetAddr)[-1] = 0xE9; sys::ValgrindDiscardTranslations((void*)(RetAddr-1), 5); @@ -442,7 +448,7 @@ void *X86JITInfo::emitGlobalValueIndirectSym(const GlobalValue* GV, void *ptr, JITCodeEmitter &JCE) { -#if defined (X86_64_JIT) +#if defined (X86_64_JIT) && defined (__LP64__) const unsigned Alignment = 8; uint8_t Buffer[8]; uint8_t *Cur = Buffer; @@ -481,7 +487,7 @@ JCE.emitAlignment(4); void *Result = (void*)JCE.getCurrentPCValue(); if (NotCC) { -#if defined (X86_64_JIT) +#if defined (X86_64_JIT) && defined (__LP64__) JCE.emitByte(0x49); // REX prefix JCE.emitByte(0xB8+2); // movabsq r10 JCE.emitWordLE((unsigned)(intptr_t)Target); @@ -496,7 +502,7 @@ return Result; } -#if defined (X86_64_JIT) +#if defined (X86_64_JIT) && defined (__LP64__) JCE.emitByte(0x49); // REX prefix JCE.emitByte(0xB8+2); // movabsq r10 JCE.emitWordLE((unsigned)(intptr_t)Target); --- tools/clang/lib/Driver/Driver.cpp.orig 2013-08-22 14:07:13.397091755 +0000 +++ tools/clang/lib/Driver/Driver.cpp 2013-08-22 14:05:55.275249307 +0000 @@ -1897,6 +1897,8 @@ // Handle pseudo-target flags '-m32' and '-m64'. // FIXME: Should this information be in llvm::Triple? if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) { + if (Target.getEnvironment() == llvm::Triple::GNUX32) + Target.setEnvironment(llvm::Triple::GNU); if (A->getOption().matches(options::OPT_m32)) { if (Target.getArch() == llvm::Triple::x86_64) Target.setArch(llvm::Triple::x86); @@ -1908,6 +1910,9 @@ if (Target.getArch() == llvm::Triple::ppc) Target.setArch(llvm::Triple::ppc64); } + } else if (Args.getLastArg(options::OPT_mx32)) { + if (Target.getArch() == llvm::Triple::x86_64) + Target.setEnvironment(llvm::Triple::GNUX32); } return Target;