|
From: | Pierre Mallard |
Subject: | Re: [Qemu-ppc] Specific use of lfs for loading int leads to wrong value in f register |
Date: | Fri, 12 Sep 2014 21:19:39 +0200 |
On 9/12/2014 2:07 AM, Pierre Mallard wrote:
> Hi,
>
> In simple float precision mode the xilinx ppc 440 's gcc (with sp_full flag) will do cast between int and float as follow :
>
> #Cast of 1023 in float
> li r0,1023
> stw r0,24(r31)
> lfs f0,24(r31) #Load int "as is" in a float register
> fcfid f0,f0 #Convert to float in place
>
> Running qemu leads to a f0 register equal to 0 before the fcfid takes place.
>
I'm not sure that I understand the instruction sequence to be a valid way to cast. Or perhaps I don't understand what you mean by "simple float precision mode".
The first two instructions result in the value 0x000003FF being written into memory. The third instruction (lfs) loads that word as a single precision number. But since PowerPC FPRs are always double precision format, there is an inherent conversion to
DP. The word in question is a denormalized single precision number and results in F0 containing the value 373FF80000000000. (see Book I, Section 4.6.2 Floating Point Load Instructions). The fcfid then interprets this data as two's complement integer and
converts to double precision floating point. The result is 0x43CB9FFC00000000 = 3.981173e+18.
QEMU gets the same answer as Power7 hardware for the above sequence.
Here is my test in case you can see something that I did incorrectly:
#include <stdint.h>
#include <stdio.h>
void cast(uint32_t *buffer, uint64_t *value)
{
asm volatile(
"li 0,1023 \n"
"stw 0,0(3) \n"
"lfs 0,0(3) \n"
"fcfid 0,0 \n"
"stfd 0,0(4) \n"
);
}
int main(int argc, char** argv)
{
uint32_t buffer = 0;
uint64_t value = 0;
cast(&buffer, &value);
printf("%016llx -> %e\n", value, *((double *)&value));
}
> While the overall cast is not a standard approach since fcfid is not meant to work on simple float precision, I would be interested in making things work on qemu.
>
> As far as I understand the code in qemu, the lfs implementation loads memory (as if destination was a 32bit) and cast it from FLOAT 32 bits to FLOAT 64 bits, allowing further computation. This works well for loading float but not in my case where lfs is
> used to load an integer.
> As far as I can imagine, the PPC itself would load the integer 32 bits without any cast and would perform the cast with fcfid from int32 to float32 in place (yes I know this is not standard).
>
> I don't see anyway to emulates this behavior in Qemu since making things work for lfs + fcfid, i.e. by not attempting to cast to float 64 in gen_qemu_ld32fs, would break a simple floating point load from memory (because this one would need an internal cast
> in 64 bits for further operation).
>
> Any idea are welcome !
>
> Pierre
>
>
[Prev in Thread] | Current Thread | [Next in Thread] |