Hello, I'm part of the (sadly fairly small) community of PS2 hackers. The current cross-toolchain for the PS2 is based on GCC 3.2.3, an outdated and buggy compiler, which I have personally gotten tired of working with, so I would like to port Clang as a newer cross-compiler for the PS2. However, the PS2 has some notable quirks which make this a non-trivial task for the current compiler. It has two main CPUs, the "Emotion Engine" (EE), which controls the main operating system, and the "I/O Processor" (IOP), which is used for PS1 compatibility and for I/O. The EE is based on a custom chip called the R5900, which implements most of MIPS III (except the ll and sc instructions, which make little sense on a single-core CPU), as well as some instructions from MIPS IV (pref, movz/movn, rsqrt.s), and a set of SIMD instructions known as Multimedia Instructions (MMI). It also contains a non-IEEE 754 single-precision FPU (which has provided a lot of headaches). It was later re-used by Toshiba as the TX79, along with a proper FPU. The IOP is based on the MIPS I R3051A, and was also used as the PS1 CPU. I'd like to go through some of the issues I've had so far. I've tried to use `mips64el` as a target, but it would invoke the system GCC with obvious bad results, so I have used the `mips64el-img-linux` target to generate ELF files which the PS2 BIOS can load (is there a better solution to generate bare-metal ELF?). I then tried to compile newlib 3.0.0-20180802, as newlib is used as the standard C library for the PS2, and hit multiple asserts, which I have attached below. I don't mind trying to fix these myself, but I would appreciate some pointers. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20180901/85a09567/attachment-0001.html> -------------- next part -------------- A non-text attachment was scrubbed... Name: llvm-bugs.tgz Type: application/gzip Size: 450900 bytes Desc: not available URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20180901/85a09567/attachment-0001.bin>
Hi Dan, On Sun, 2 Sep 2018 at 22:14, Dan Ravensloft via llvm-dev <llvm-dev at lists.llvm.org> wrote:> I then tried to compile newlib 3.0.0-20180802, as newlib is used as the standard C library for the PS2, and hit multiple asserts, which I have attached below.After a quick look, three of the issues seem to be related to "long double", which is translated to fp128: vfprintf: invalid bitcast from f128 to f64. Part of some call, maybe? ldtoa: obviously a function taking "long double". vfscanf: Mishandling return of f128 from a libcall. Now, mapping long double to fp128 is actually a choice you have as an ABI creator. It's possible you feel constrained to follow GCC here and so need that, but if not the simplest fix might well be to just declare long double is the same as double. PS2 doesn't strike me as a system where you'd often want a 128-bit float. You'd do that by modifying tools/clang/lib/Basic/Targets/Mips.h (the setN32N64ABITypes function, notice FreeBSD has already done this). If you do have to support f128, you'd probably start by focusing on MipsISelLowering.cpp. Specifically the functions named things like LowerFormalArguments, LowerCall, LowerReturn. I'm not sure what the ABI is likely to be there, but I suspect you'll end up assigning an fp128 to 2 64-bit integer registers. If needed I'm sure me or a Mips expert could provide more details. The other problem (lrintfp) seems to involve an invalid truncation from f32 to f64, possibly inserted by code unaware of the single-float option. Nothing looks obviously wrong, so it's the usual debugging procedure: 1. Try to produce a reduced test-case 2. gdb/lldb it, since not many places produce the Mips-specific TruncIntFP node that's causing the problem. For 1, I've actually already got one for you: void foo(float *in, long long *out) { *out = *in; } In brief, how I got it was: 1. Run lldb on the crashing Clang command. Go up the backtrace until I got usable C++ code. DAG.viewGraph() produces a very nice pictorial representation of the code being selected, it had load(f32) -> MipsISD::TruncIntFP (f64) -> store. That middle trunc is obviously really dodgy. 2. From there you could try to write IR that did the same thing. Instead I printed "BlockName" that was available in one of the frames. Then I dumped the IR from Clang (-emit-llvm) and just looked at that IR snippet: %23 = load float, float* %x.addr, align 4 %conv33 = fptosi float %23 to i64 store i64 %conv33, i64* %retval, align 8 br label %return>From there it's a lot easier to write down the C function I gave,which is what I did. So the next step is to debug where Mips is producing those TruncIntFP nodes. There'll be some constraint it's not checking or an unexpected node type, probably related to -msingle-float. I'm afraid I'm not sure what yet. Cheers. Tim.
Thanks Tim, that's actually a very useful guide, and debugging this is going to be much easier with that knowledge. First step: rebuild Clang. On Mon, 3 Sep 2018 at 13:31, Tim Northover <t.p.northover at gmail.com> wrote:> Hi Dan, > > On Sun, 2 Sep 2018 at 22:14, Dan Ravensloft via llvm-dev > <llvm-dev at lists.llvm.org> wrote: > > I then tried to compile newlib 3.0.0-20180802, as newlib is used as the > standard C library for the PS2, and hit multiple asserts, which I have > attached below. > > After a quick look, three of the issues seem to be related to "long > double", which is translated to fp128: > > vfprintf: invalid bitcast from f128 to f64. Part of some call, maybe? > ldtoa: obviously a function taking "long double". > vfscanf: Mishandling return of f128 from a libcall. > > Now, mapping long double to fp128 is actually a choice you have as an > ABI creator. It's possible you feel constrained to follow GCC here and > so need that, but if not the simplest fix might well be to just > declare long double is the same as double. PS2 doesn't strike me as a > system where you'd often want a 128-bit float. You'd do that by > modifying tools/clang/lib/Basic/Targets/Mips.h (the setN32N64ABITypes > function, notice FreeBSD has already done this). > > If you do have to support f128, you'd probably start by focusing on > MipsISelLowering.cpp. Specifically the functions named things like > LowerFormalArguments, LowerCall, LowerReturn. I'm not sure what the > ABI is likely to be there, but I suspect you'll end up assigning an > fp128 to 2 64-bit integer registers. If needed I'm sure me or a Mips > expert could provide more details. > > The other problem (lrintfp) seems to involve an invalid truncation > from f32 to f64, possibly inserted by code unaware of the single-float > option. Nothing looks obviously wrong, so it's the usual debugging > procedure: > > 1. Try to produce a reduced test-case > 2. gdb/lldb it, since not many places produce the Mips-specific > TruncIntFP node that's causing the problem. > > For 1, I've actually already got one for you: > > void foo(float *in, long long *out) { > *out = *in; > } > > In brief, how I got it was: > 1. Run lldb on the crashing Clang command. Go up the backtrace until I > got usable C++ code. DAG.viewGraph() produces a very nice pictorial > representation of the code being selected, it had load(f32) -> > MipsISD::TruncIntFP (f64) -> store. That middle trunc is obviously > really dodgy. > 2. From there you could try to write IR that did the same thing. > Instead I printed "BlockName" that was available in one of the frames. > Then I dumped the IR from Clang (-emit-llvm) and just looked at that > IR snippet: > > %23 = load float, float* %x.addr, align 4 > %conv33 = fptosi float %23 to i64 > store i64 %conv33, i64* %retval, align 8 > br label %return > > From there it's a lot easier to write down the C function I gave, > which is what I did. > > So the next step is to debug where Mips is producing those TruncIntFP > nodes. There'll be some constraint it's not checking or an unexpected > node type, probably related to -msingle-float. I'm afraid I'm not sure > what yet. > > Cheers. > > Tim. >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20180903/74c4005c/attachment.html>
On Mon, 3 Sep 2018 at 13:31, Tim Northover <t.p.northover at gmail.com> wrote:> So the next step is to debug where Mips is producing those TruncIntFP > nodes. There'll be some constraint it's not checking or an unexpected > node type, probably related to -msingle-float. I'm afraid I'm not sure > what yet. >I'm reasonably sure the function producing that node is lowerFP_TO_SINT_STORE in lib/Target/Mips/MipsISelLowering.cpp. The node before that function executes has an fp_to_sint node which seems to want to convert an i64 to an f32 which seems...rather odd to me, honestly. The PS2, for what it's worth, only has an i32 -> f32 instruction, so I think there's an impedance mismatch somewhere. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20180906/c3ca7ed0/attachment.html>