Porting to System z

Hi,
I am beginning the porting process for Linux on System z (aka IBM
Mainframe). I thought I¹d build LLVM first with the c and cpp backends so
that tools like TableGen would be created that I¹d then use to process the
.td files that I¹ll be creating. So I used svn to grab the code from the
repository and ran configure and make. However, the build breaks at this
point:

llvm[1]: Building Intrinsics.gen.tmp from Intrinsics.td
tblgen: IntrinsicEmitter.cpp:163: void EmitTypeForValueType(std::ostream&,
llvm::MVT::SimpleValueType): Assertion `false && "Unsupported ValueType!"'
failed.
0 tblgen 0x00000000801be2bc
1 tblgen 0x00000000801bea14
2 tblgen 0x000003ffffad4b84
3 libc.so.6 0x0000020000286ef0 gsignal + 76
4 libc.so.6 0x0000020000288330 abort + 256
5 libc.so.6 0x000002000027ed08 __assert_fail + 228
6 tblgen 0x0000000080111f86
7 tblgen 0x0000000080112afe
8 tblgen 0x000000008011281c
9 tblgen 0x0000000080113354
10 tblgen 0x0000000080113744
11 tblgen 0x000000008019273e main + 2650
12 libc.so.6 0x0000020000270598 __libc_start_main + 256
13 tblgen 0x0000000080009ec2 std::__throw_logic_error(char const*) + 158
Stack dump:
0. Program arguments: /home/neale/LLVM/llvm/Debug/bin/tblgen -I
/home/neale/LLVM/llvm/lib/VMCore -I /home/neale/LLVM/llvm/include -I
/home/neale/LLVM/llvm/include -I /home/neale/LLVM/llvm/lib/Target
/home/neale/LLVM/llvm/include/llvm/Intrinsics.td -o
/home/neale/LLVM/llvm/lib/VMCore/Debug/Intrinsics.gen.tmp -gen-intrinsic
make[1]: *** [/home/neale/LLVM/llvm/lib/VMCore/Debug/Intrinsics.gen.tmp]
Aborted

Is this a known problem? Would it be better to build the tools etc. using a
"stable" tarball and just use the svn sources so I can generate the patches
for adding System z?

Neale

Hi,

llvm[1]: Building Intrinsics.gen.tmp from Intrinsics.td
tblgen: IntrinsicEmitter.cpp:163: void EmitTypeForValueType(std::ostream&,
llvm::MVT::SimpleValueType): Assertion `false && "Unsupported ValueType!"'
failed.

this came up before IIRC, but I don't remember the details - buggy system
compiler? Try searching the archives. Also, if you were compiling with
optimization, try building without optimization.

Ciao,

Duncan.

I searched the archives and found this from last month:

I ran into the same problem and fixed it by forcing the
MVT::SimpleValueType enum to be 64 bits so that all of the types
in the union later in the class are the same size. I tested this
on ppc64 and x86_64.

Index: include/llvm/CodeGen/ValueTypes.h

Hi Neale,

The comment in the above fix indicates that in this 64-bit system the enum
needs to be 64-bits is correct, but the fix doesn't seem to do it.

the basic problem seems to be that your system compiler is miscompiling
LLVM. Mucking around with the details of the union in the hope of tricking
the compiler into not miscompiling is one approach, but as you saw each
broken compiler tends to be broken differently :slight_smile: I'm quite surprised
though because you said you are using gcc 4.3 (right?). This may be a
sign that something is wrong in LLVM rather than in the system compiler...
Did it work when building without optimization?

Ciao,

Duncan.

No it didn't work without optimization. Looking at all the C++ manuals etc.
the idea of forcing an enum to a different size is a practice fraught with
danger. It appears gcc 4.3.3 insists on sizeof(enum) == sizeof(int) so the
union trick is not going to work. Is there any reason it needs to be an
enum? Could SimpleValueType be a typedef long which means the union would
work for _LP64 and _LP32 systems?

Neale

Hello,

+static const uintptr_t minus_one = -1;

-1 here is of signed int type. What if you will use -1ULL ?

* Neale Ferguson:

So the SimpleTy variable which is a SimpleTypeValue is behaving strangely.
It's found within a private definition:

    union {
      uintptr_t V;
      SimpleValueType SimpleTy;
      const Type *LLVMTy;
    };

The comment in the above fix indicates that in this 64-bit system the enum
needs to be 64-bits is correct, but the fix doesn't seem to do it.

What's the union being used for? I wouldn't be surprised if this is
pushing into undefined territory.

Yes, that works much better. However, I fear the problem is more to do with
trying to force enums to be a different size which appears not to be
supported by most compilers. The IBM C++ compiler apparently has a #pragma
which can be used to do it and gcc 4.3 seems to be happy with the hack
described but as Duncan says trying to force this behavior in a union is
probably less than desirable in the long term.

Another ugly hack that I tried:

    union {
      uintptr_t V;
#ifdef _LP64
      SimpleValueType SimpleTyU[2];
# define SimpleTy SimpleTyU[1]
#else
      SimpleValueType SimpleTyU[1];
# define SimpleTy SimpleTyU[0]
#endif
      const Type *LLVMTy;
    };

This works on my big endian 64-bit system but I've not seen what damage it
may do on other platform types.

It's used throughout the TableGen code for doing things such as isInteger(),
isFloat()...

Hi Neale,

Yes, that works much better. However, I fear the problem is more to do with
trying to force enums to be a different size which appears not to be
supported by most compilers. The IBM C++ compiler apparently has a #pragma
which can be used to do it and gcc 4.3 seems to be happy with the hack
described but as Duncan says trying to force this behavior in a union is
probably less than desirable in the long term.

I don't know if the union is invoking undefined behaviour or not, but given
the number of compilers it breaks it clearly needs to be changed. I'm not sure
the enum needs to be an enum, how about turning it into a uintptr_t instead?

Ciao,

Duncan.

That's fine with me. It's all encapsulated within the MVT class so
it should be pretty easy to change.

Dan