On Sun, 2 Sep 2018 at 22:14, Dan Ravensloft via llvm-dev
<llvm...@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.
_______________________________________________
LLVM Developers mailing list
llvm...@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
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.
That doesn't surprise me.
> 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.
It's a pretty common kind of operation. C says you're allowed to cast
an int64_t to a float, and that's the IR you get when you try.
> The PS2, for what it's worth, only has an i32 -> f32 instruction, so I think there's an impedance mismatch somewhere.
This is also a fairly common situation. If the operation can be
emulated with a reasonably small number of native instructions you can
often get LLVM to do that.
In this case it would probably be a libcall though because it's quite
complex. LLVM would generate a call to __floatdisf, which will be
provided by compiler-rt (there are C implementations for all kinds of
floating-point operations there).
You should see the same thing if you compile a function doing that
conversion with GCC.
On 6 Sep 2018, at 08:00, Dan Ravensloft via llvm-dev <llvm...@lists.llvm.org> wrote:On Mon, 3 Sep 2018 at 13:31, Tim Northover <t.p.no...@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.
On 6 Sep 2018, at 08:00, Dan Ravensloft via llvm-dev <llvm...@lists.llvm.org> wrote:On Mon, 3 Sep 2018 at 13:31, Tim Northover <t.p.no...@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.FWIW, I'm not sure how well tested -msingle-float was on MIPS. I don't think we had any bots testing it.
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.Did you mean those types to be the other way around? fp_to_sint is supposed to take a floating point type and produce an integer type so if you're seeing them backwards like this then that would definitely be a bug.
> The PS2, for what it's worth, only has an i32 -> f32 instruction, so I think there's an impedance mismatch somewhere.
This is also a fairly common situation. If the operation can be
emulated with a reasonably small number of native instructions you can
often get LLVM to do that.
In this case it would probably be a libcall though because it's quite
complex. LLVM would generate a call to __floatdisf, which will be
provided by compiler-rt (there are C implementations for all kinds of
floating-point operations there).
You should see the same thing if you compile a function doing that
conversion with GCC.
Cheers.
Tim.
I suspect so, though I'm not familiar enough with MIPS or the PS2 to
be 100% sure -- checking what GCC does in this case would be good
confirmation.
> If so, would you mind pointing me to a function which performs this, or otherwise give a high-level description of how this is done?
I *think* you should be able to just tell the lower function to ignore
this case (maybe based on the types, maybe just because we're in
SingleFloat mode, I'll need to read more code to be sure). Then the
generic handling should get involved and expand it to a libcall if the
operation isn't natively supported.
On Thu, 6 Sep 2018 at 17:55, Dan Ravensloft <dan.rav...@gmail.com> wrote:
> If so, would you mind pointing me to a function which performs this, or otherwise give a high-level description of how this is done?
I just did a very quick experiment where I made lowerFP_TO_SINT and
lowerFP_TO_SINT_STORE return SDValue() (which is the marker for "I
don't want to handle this"). It looks like someone was enthusiastic
enough to think this operation did actually deserve inlining (by
TargetLowering::expandFP_TO_SINT) so instead of a libcall it produces
a bunch of weird operations implementing that. I assume they're right,
but haven't checked.
To make it production-quality you'd want to predicate the changes I
made on Subtarget->isSingleFloat() I think (probably in combination
with the actual types, since f32 -> i32 ought to still be OK with the
existing code). The main annoyance there is that lowerFP_TO_SINT_STORE
is static rather than a member of MipsISelLowering so it doesn't have
access to Subtarget. Personally, I'd just make it a member function to
fix that.
I just did a very quick experiment where I made lowerFP_TO_SINT and
lowerFP_TO_SINT_STORE return SDValue() (which is the marker for "I
don't want to handle this").
To make it production-quality you'd want to predicate the changes I
made on Subtarget->isSingleFloat() I think (probably in combination
with the actual types, since f32 -> i32 ought to still be OK with the
existing code). The main annoyance there is that lowerFP_TO_SINT_STORE
is static rather than a member of MipsISelLowering so it doesn't have
access to Subtarget. Personally, I'd just make it a member function to
fix that.
Cheers.
Tim.
Hi,Years ago, I got to go through the magical adventure of building a working Cell compiler based on LLVM / Clang for the PS3. It was supposed to be open sourced / upstreamed to llvm, but of course the company didn't want to pay for the extra hours that would take. :P
I'm not sure how bad the GCC compiler for PS2 is, but if it's anything like the PS3 one I'd suggest to watch out that any Sony ABI docs probably have glaring faults somewhere. :D
I don't know how much I can help with the PS2 / EE but I've noticed that some of that type of design stuff tends to persist so when you get to that area of it let me know if you run into any problems and they might refresh my memory on something that can help; never know.
I've got a debug/test PS3 with a hardware Emotion Engine as well if you want any spot checks on that particular version of the platform. I'm guessing the actual debugging part is either already covered or easier via an emulator + PC at this point, and I don't have it set up for that.
Just thought I'd offer, not much but it can't hurt when diving into that kind of "fun" :D :DCheers,-G
Strange. I only tested it on a simple reproducer rather than newlib:
void foo(float *in, long long *out) {
*out = *in;
}
$ clang -target mips64el-img-linux -mcpu=mips3 -S -o- -Os tmp.c
[...]
Is it possible you were hitting a different error with roughly similar output?
> lowerFP_TO_SINT_STORE is only ever called by lowerFP_TO_SINT, so I'm just passing single-floatness (we need a better name for that) as an argument to lowerFP_TO_SINT_STORE at the moment.
Are you sure? I see it being called by lowerSTORE.
On Fri, 7 Sep 2018 at 07:38, Dan Ravensloft <dan.rav...@gmail.com> wrote:
> I just tried this, but the compiler still crashes with the same error. Maybe our experiments were different.
Strange. I only tested it on a simple reproducer rather than newlib:
void foo(float *in, long long *out) {
*out = *in;
}
$ clang -target mips64el-img-linux -mcpu=mips3 -S -o- -Os tmp.c
[...]
Is it possible you were hitting a different error with roughly similar output?
> lowerFP_TO_SINT_STORE is only ever called by lowerFP_TO_SINT, so I'm just passing single-floatness (we need a better name for that) as an argument to lowerFP_TO_SINT_STORE at the moment.
Are you sure? I see it being called by lowerSTORE.
$ clang -target mips64el-img-linux -mcpu=mips3 -S -o- -Os tmp.c
Oops, yes, I was then. Fortunately not last night though, and my Clang
still works with -msingle-float.
I looked at your diffs and you've only changed one of the functions to
return SDValue(), you need to change lowerFP_TO_SINT itself too. The
one with the store is just there as an optimization; if it doesn't
trigger (because of your diff) then lowerFP_TO_SINT will still create
a bad node afterwards.
I looked at your diffs and you've only changed one of the functions to
return SDValue(), you need to change lowerFP_TO_SINT itself too. The
one with the store is just there as an optimization; if it doesn't
trigger (because of your diff) then lowerFP_TO_SINT will still create
a bad node afterwards.
Excellent!
> I think the lrint fix should be upstreamed right away; would you mind if I credited you in the patch?
Not at all. Thanks!
Hi Dan,
In case you are interested in the baremetal libgloss bits, I made some
changes to get that to compile with clang in
<https://github.com/CTSRD-CHERI/newlib>. This also contains some
unrelated changes to make it easier to use on QEMU MALTA and to build
in CHERI pure-capability mode but the changes to the MIPS crt0 bits
might be useful.
I believe <https://github.com/CTSRD-CHERI/newlib/commit/2e686345f77a1b745e504ffdbdf012ec78fbfc74>
and possibly some follow-up commits should be sufficient to compile
libgloss with clang (at least for MIPS64).
Alex
> Cheers, Tim!
On Sat, 8 Sep 2018 at 15:01, Tim Northover <t.p.no...@gmail.com> wrote:At the moment I'm really quite confused about where that PseudoCVT_S_L
is coming from though, the pattern generating it ought to be disabled.I commented out that pattern and Clang now complains about not being able to select a valid instruction, but it doesn't segfault, suggesting that pattern is definitely causing the crash.
Hi Dan,This is pretty interesting. Do you have a project page (or something) that I can check out?
_______________________________________________