qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-ppc] Specific use of lfs for loading int leads to wrong value


From: Tom Musta
Subject: Re: [Qemu-ppc] Specific use of lfs for loading int leads to wrong value in f register
Date: Fri, 12 Sep 2014 08:48:31 -0500
User-agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.6.0

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
> 
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]