XMM register instructions and their c equivalents

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
2
down vote

favorite
2












I'm trying to convert some x86 assembly back into C++, and I cannot figure out how this set of instructions was originally written.



movd xmm0,eax ; byte read from device '0x04'
cvtdq2pd xmm0,xmm0 ; convert packed to double?
shr eax,0x1F ; highest bit
addsd xmm0,qword ptr ds:[eax*8+0x4F6CC0] ; global [0, 4294967296] if I read it right
cvtpd2ps xmm0,xmm0 ; double to packed?
movss dword ptr ds:[ebx+0x34],xmm0 ; store the result


I've tried various forms of casting float and double to other data types on Compiler Explorer but I cannot find anything that reproduces the cvtdq2pd and cvtpd2ps instructions.



What would the above code look like in c/c++ and what is the resulting data type?







share|improve this question
















  • 1




    I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
    – Rup
    Sep 7 at 0:41














up vote
2
down vote

favorite
2












I'm trying to convert some x86 assembly back into C++, and I cannot figure out how this set of instructions was originally written.



movd xmm0,eax ; byte read from device '0x04'
cvtdq2pd xmm0,xmm0 ; convert packed to double?
shr eax,0x1F ; highest bit
addsd xmm0,qword ptr ds:[eax*8+0x4F6CC0] ; global [0, 4294967296] if I read it right
cvtpd2ps xmm0,xmm0 ; double to packed?
movss dword ptr ds:[ebx+0x34],xmm0 ; store the result


I've tried various forms of casting float and double to other data types on Compiler Explorer but I cannot find anything that reproduces the cvtdq2pd and cvtpd2ps instructions.



What would the above code look like in c/c++ and what is the resulting data type?







share|improve this question
















  • 1




    I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
    – Rup
    Sep 7 at 0:41












up vote
2
down vote

favorite
2









up vote
2
down vote

favorite
2






2





I'm trying to convert some x86 assembly back into C++, and I cannot figure out how this set of instructions was originally written.



movd xmm0,eax ; byte read from device '0x04'
cvtdq2pd xmm0,xmm0 ; convert packed to double?
shr eax,0x1F ; highest bit
addsd xmm0,qword ptr ds:[eax*8+0x4F6CC0] ; global [0, 4294967296] if I read it right
cvtpd2ps xmm0,xmm0 ; double to packed?
movss dword ptr ds:[ebx+0x34],xmm0 ; store the result


I've tried various forms of casting float and double to other data types on Compiler Explorer but I cannot find anything that reproduces the cvtdq2pd and cvtpd2ps instructions.



What would the above code look like in c/c++ and what is the resulting data type?







share|improve this question












I'm trying to convert some x86 assembly back into C++, and I cannot figure out how this set of instructions was originally written.



movd xmm0,eax ; byte read from device '0x04'
cvtdq2pd xmm0,xmm0 ; convert packed to double?
shr eax,0x1F ; highest bit
addsd xmm0,qword ptr ds:[eax*8+0x4F6CC0] ; global [0, 4294967296] if I read it right
cvtpd2ps xmm0,xmm0 ; double to packed?
movss dword ptr ds:[ebx+0x34],xmm0 ; store the result


I've tried various forms of casting float and double to other data types on Compiler Explorer but I cannot find anything that reproduces the cvtdq2pd and cvtpd2ps instructions.



What would the above code look like in c/c++ and what is the resulting data type?









share|improve this question











share|improve this question




share|improve this question










asked Sep 6 at 22:18









Twifty

2078




2078







  • 1




    I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
    – Rup
    Sep 7 at 0:41












  • 1




    I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
    – Rup
    Sep 7 at 0:41







1




1




I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
– Rup
Sep 7 at 0:41




I'd guess the first four lines are loading an unsigned 32-bit value into a double: if cvtdq2pd treats the input as signed then you'd need to add 1<<32 to correct the output if the top bit of the input is set.
– Rup
Sep 7 at 0:41










1 Answer
1






active

oldest

votes

















up vote
8
down vote



accepted










You likely won't get an exact reproduction because cvtdq2pd takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax here, there are probably better(?) instructions to use.



cvtsi2sd xmm0, eax



will do the same thing as



movd xmm0,eax



cvtdq2pd xmm0,xmm0



See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html



So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.




Onto your actual question:



cvtpd2ps xmm0,xmm0 ; double to packed?




CVTPD2PS xmm1, xmm2/m128



Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.




This will pack the two double precision floats at xmm0[0:63] & xmm0[64:127] into the lower 64 bits of xmm0, converting them from double to single precision floating point values (xmm0[0:31] & xmm0[32:63]).



Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html



So if the lower 64 bits of xmm0 represented a double, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0.



movss dword ptr ds:[ebx+0x34],xmm0




MOVSS xmm2/m32, xmm1



Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.




Now stores the 4 byte result from xmm0[0:31] into [ebx+0x34], which we know is a single precision float from the result of the cvtpd2ps operation.



So the result of this operation is a 32 bit float.



Ref: https://www.felixcloutier.com/x86/MOVSS.html




This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.



double* d_arr = (double*)0x4F6CC0;

int main()

int in = 4;
int signbit = ((unsigned int)in >> 31);
float result = *(double*)(d_arr + signbit) + in;
return 0;




Conclusion:



cvtdq2pd & cvtpd2ps are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0 are never relevant to the result.



Disclaimer:



I've never used floating point assembly before. I just looked up the docs now. I could be missing something.






share|improve this answer






















    Your Answer







    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "489"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    noCode: true, onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2freverseengineering.stackexchange.com%2fquestions%2f19275%2fxmm-register-instructions-and-their-c-equivalents%23new-answer', 'question_page');

    );

    Post as a guest






























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    8
    down vote



    accepted










    You likely won't get an exact reproduction because cvtdq2pd takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax here, there are probably better(?) instructions to use.



    cvtsi2sd xmm0, eax



    will do the same thing as



    movd xmm0,eax



    cvtdq2pd xmm0,xmm0



    See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html



    So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.




    Onto your actual question:



    cvtpd2ps xmm0,xmm0 ; double to packed?




    CVTPD2PS xmm1, xmm2/m128



    Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.




    This will pack the two double precision floats at xmm0[0:63] & xmm0[64:127] into the lower 64 bits of xmm0, converting them from double to single precision floating point values (xmm0[0:31] & xmm0[32:63]).



    Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html



    So if the lower 64 bits of xmm0 represented a double, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0.



    movss dword ptr ds:[ebx+0x34],xmm0




    MOVSS xmm2/m32, xmm1



    Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.




    Now stores the 4 byte result from xmm0[0:31] into [ebx+0x34], which we know is a single precision float from the result of the cvtpd2ps operation.



    So the result of this operation is a 32 bit float.



    Ref: https://www.felixcloutier.com/x86/MOVSS.html




    This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.



    double* d_arr = (double*)0x4F6CC0;

    int main()

    int in = 4;
    int signbit = ((unsigned int)in >> 31);
    float result = *(double*)(d_arr + signbit) + in;
    return 0;




    Conclusion:



    cvtdq2pd & cvtpd2ps are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0 are never relevant to the result.



    Disclaimer:



    I've never used floating point assembly before. I just looked up the docs now. I could be missing something.






    share|improve this answer


























      up vote
      8
      down vote



      accepted










      You likely won't get an exact reproduction because cvtdq2pd takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax here, there are probably better(?) instructions to use.



      cvtsi2sd xmm0, eax



      will do the same thing as



      movd xmm0,eax



      cvtdq2pd xmm0,xmm0



      See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html



      So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.




      Onto your actual question:



      cvtpd2ps xmm0,xmm0 ; double to packed?




      CVTPD2PS xmm1, xmm2/m128



      Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.




      This will pack the two double precision floats at xmm0[0:63] & xmm0[64:127] into the lower 64 bits of xmm0, converting them from double to single precision floating point values (xmm0[0:31] & xmm0[32:63]).



      Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html



      So if the lower 64 bits of xmm0 represented a double, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0.



      movss dword ptr ds:[ebx+0x34],xmm0




      MOVSS xmm2/m32, xmm1



      Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.




      Now stores the 4 byte result from xmm0[0:31] into [ebx+0x34], which we know is a single precision float from the result of the cvtpd2ps operation.



      So the result of this operation is a 32 bit float.



      Ref: https://www.felixcloutier.com/x86/MOVSS.html




      This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.



      double* d_arr = (double*)0x4F6CC0;

      int main()

      int in = 4;
      int signbit = ((unsigned int)in >> 31);
      float result = *(double*)(d_arr + signbit) + in;
      return 0;




      Conclusion:



      cvtdq2pd & cvtpd2ps are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0 are never relevant to the result.



      Disclaimer:



      I've never used floating point assembly before. I just looked up the docs now. I could be missing something.






      share|improve this answer
























        up vote
        8
        down vote



        accepted







        up vote
        8
        down vote



        accepted






        You likely won't get an exact reproduction because cvtdq2pd takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax here, there are probably better(?) instructions to use.



        cvtsi2sd xmm0, eax



        will do the same thing as



        movd xmm0,eax



        cvtdq2pd xmm0,xmm0



        See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html



        So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.




        Onto your actual question:



        cvtpd2ps xmm0,xmm0 ; double to packed?




        CVTPD2PS xmm1, xmm2/m128



        Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.




        This will pack the two double precision floats at xmm0[0:63] & xmm0[64:127] into the lower 64 bits of xmm0, converting them from double to single precision floating point values (xmm0[0:31] & xmm0[32:63]).



        Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html



        So if the lower 64 bits of xmm0 represented a double, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0.



        movss dword ptr ds:[ebx+0x34],xmm0




        MOVSS xmm2/m32, xmm1



        Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.




        Now stores the 4 byte result from xmm0[0:31] into [ebx+0x34], which we know is a single precision float from the result of the cvtpd2ps operation.



        So the result of this operation is a 32 bit float.



        Ref: https://www.felixcloutier.com/x86/MOVSS.html




        This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.



        double* d_arr = (double*)0x4F6CC0;

        int main()

        int in = 4;
        int signbit = ((unsigned int)in >> 31);
        float result = *(double*)(d_arr + signbit) + in;
        return 0;




        Conclusion:



        cvtdq2pd & cvtpd2ps are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0 are never relevant to the result.



        Disclaimer:



        I've never used floating point assembly before. I just looked up the docs now. I could be missing something.






        share|improve this answer














        You likely won't get an exact reproduction because cvtdq2pd takes the lower 64 bits of the second operand but since we're limited to 32 bits because we're using eax here, there are probably better(?) instructions to use.



        cvtsi2sd xmm0, eax



        will do the same thing as



        movd xmm0,eax



        cvtdq2pd xmm0,xmm0



        See here https://www.felixcloutier.com/x86/CVTDQ2PD.html & https://www.felixcloutier.com/x86/CVTSI2SD.html



        So really what it's doing is converting a 32 bit signed integer value into a double precision floating point.




        Onto your actual question:



        cvtpd2ps xmm0,xmm0 ; double to packed?




        CVTPD2PS xmm1, xmm2/m128



        Convert two packed double-precision floating-point values in xmm2/mem to two single-precision floating-point values in xmm1.




        This will pack the two double precision floats at xmm0[0:63] & xmm0[64:127] into the lower 64 bits of xmm0, converting them from double to single precision floating point values (xmm0[0:31] & xmm0[32:63]).



        Ref: https://www.felixcloutier.com/x86/CVTPD2PS.html



        So if the lower 64 bits of xmm0 represented a double, it's now been converted to a 32 bit float, which now sits in the lower 32 bits of xmm0.



        movss dword ptr ds:[ebx+0x34],xmm0




        MOVSS xmm2/m32, xmm1



        Move scalar single-precision floating-point value from xmm1 register to xmm2/m32.




        Now stores the 4 byte result from xmm0[0:31] into [ebx+0x34], which we know is a single precision float from the result of the cvtpd2ps operation.



        So the result of this operation is a 32 bit float.



        Ref: https://www.felixcloutier.com/x86/MOVSS.html




        This code here should be a reasonable approximation. In Godbolt it gives me similar assembly to what you have.



        double* d_arr = (double*)0x4F6CC0;

        int main()

        int in = 4;
        int signbit = ((unsigned int)in >> 31);
        float result = *(double*)(d_arr + signbit) + in;
        return 0;




        Conclusion:



        cvtdq2pd & cvtpd2ps are too powerful for what's actually being calculated here. Unless I'm reading this totally wrong, the upper 64 bits of xmm0 are never relevant to the result.



        Disclaimer:



        I've never used floating point assembly before. I just looked up the docs now. I could be missing something.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Sep 7 at 8:29









        0xC0000022L♦

        7,48742860




        7,48742860










        answered Sep 7 at 1:41









        Abigail

        3216




        3216



























             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2freverseengineering.stackexchange.com%2fquestions%2f19275%2fxmm-register-instructions-and-their-c-equivalents%23new-answer', 'question_page');

            );

            Post as a guest













































































            Comments

            Popular posts from this blog

            Long meetings (6-7 hours a day): Being “babysat” by supervisor

            Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

            Confectionery