[RFC PATCH] X32 ABI support for Clang/compiler-rt

>
> > >
> > > > > Hi Steven,
> > > > >
> > > > > This looks interesting and raises a number of questions :slight_smile:
> > > > >
> > > > > 1) Does applying this patch actually bring working sanitizers to x32
> > > > > platform?
> > > > > That is, after you build the clang, does "clang -fsanitize=whatever
> > > > foo.c"
> > > > > compile/link/run with expected results?
> > > > > I doubt that, as there is some platform-specific code in all the
> > > > > sanitizers, and many of them heavily depend
> > > > > on the address space layout. Porting TSan and MSan to 32-bit address
> > > > space
> > > > > is especially hard, and we don't plan
> > > > > to do this anytime soon. I think it makes sense to build only the
> > > > libraries
> > > > > that are expected to work on a given arch.
> > > > >
> > > > I should have made clear this is very much a WIP. I expect to have make
> > > > an effort to port compiler-rt, but first I need to be able to generate
> > > > elf32_x86_64 objects with Clang. I confess, my method of porting code
> > > > to x32 so far has consisted of trying to build existing code and
> > > > modifying what breaks, or disabling features where inapplicable. I
> > > > haven't studied the code well enough to understand and predict where
> > I'm
> > > > going to have make modification in advance. It's worked so far with
> > > > most things I've attempted but LLVM/Clang/compiler-rt is an order of
> > > > magnitude more complex than anything else I've poked at. The biggest
> > > > success I've had so far with this method is porting of Mozilla
> > > > Spidermonkey/js17.
> > > >
> > >
> > > So, IIUC, if you're working on making LLVM/Clang/compiler-rt source tree
> > > build on x32 host, I suggest your first step should be: disable building
> > > compiler-rt
> > > on x32 host :slight_smile: One of the reasons: in makefile-based build compiler-rt
> > > sources
> > > are compiled with just-built Clang (I honestly don't know if Clang can
> > > target x32
> > > at the moment). Another reason: compiler-rt code is really arch-specific,
> > > and even
> > > if it compiles, it wouldn't work.
> > >
> > See accompanied Clang patch in other email. I've attempted to get Clang
> > to target x32, I'm also suspicious that x32 built clang isn't correctly
> > working to produce 64-bit code, but that's a somewhat different bug that
> > I haven't yet attempted to address. Without modifying Clang to target
> > x32, the x32 *built* Clang fails to compile compiler-rt with -m64, I
> > need help decoding the crash backtrace to figure out where that bug
> > lies, but it's not related to (or helped by) my patch.
> >
>
> So, it looks like Clang built on x32 host:
> (a) doesn't work with -m64 (can't target x86_64)
> (b) can target x32 with your patch.
> If that's the case, (a) should be investigated (maybe, you can open a bug
> for this
> as a start), while you should try to get your patch for (b) submitted.
> Let's move the
> discussion to that thread, most likely you'll have to add tests and find a
> reviewer for that patch.
>
Actually, I've just fixed a bug where when running on a x32 host the
Environment part of the Triple is always GNUX32, I've now changed it so
that it gets properly set to GNU. This *fixes* the -m64 case, since
otherwise it *always* tries to compile to ILP32 except for some reason
the object ends up as elf_x86_64, not sure why yet... (can anybody help
here?) The -m32 case worked because then the Arch component was set to
i386 which is !=x86_64 as protects all the GNUX32 tests for throughout
the patch.

The upshot of this is the x86_64 target is now working on x32 hosts for
the first time! :slight_smile:

Unfortunately, it does reveal a problem with X32; or possibly it's just
that atomic.c from compiler-rt won't work as is with X32 target, but it
shouldn't be triggering a crash...

As noted above, since the object file is ending up as elf_x86_64 it's
probably not surprising that it's crashing. The question is what did I
miss?

This chunk (largely unchanged from the original patch sent to llvm-dev
last year) should be doing the trick, so why doesn't it?

This patch is still not creating elf32_x86_64 objects. No idea
why. :frowning: It does however, fix elf_x86_64 (-m64) code generation on x32
hosts which is nice. :slight_smile:

--- ./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-"

I know why. I had assumed Michael Liao (the original patch author) had
submitted all the _LLVM_ x32 support as separate patches, and it was
just the tests/Clang/compiler-rt support that was missing. It seems not
so. Those specific patches he did submit got commited, but many pieces
are missing... I should NEVER make such big assumptions!

Looks like I'm going to have to go through the original patch and create
a new patch series.

If I'm going to submit the Clang patch, how should it be submitted? One
patch with what's required to get x32 host to work, then another
enabling x32 code generation once the required changes to llvm are
merged? Would that be sufficient?

Sounds good to me.

Dmitri

Been chatting with jfb on irc. It seems Google NaCl has all the needed
changes to get LLVM to work with x32, in addition to their other
requirements, so I'm going to go through their changes and make relevant
parts conditional on GNUX32. Then when their code lands which they hope
won't be too long x32 will come for free.

Please note that the bulk of work to make Clang x32-capable is in LLVM. The
patches sent by Michael a while back no longer apply because we upstreamed
some things since then, but the support is not complete yet (mainly in
SelDAG). Please be sure to go over the mailing list archives discussing
x32, as well as look at the SVN logs for everything mentioning x32. There's
quite a bit of history here and it's important to have a full grasp of
things.

Eli