Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Math.Atan2 and FPATAN

I'm writing some math code in C#, forcing it to compile for x86 in release, optimized, and I'm looking at the disassembly in windbg. It's usually pretty good, often writing better assembly than I could (not that I'm all that good at assembly, but there you go).

However, I've noticed that this function:

static void TemporaryWork()
{
    double x = 4;
    double y = 3;
    double z = Math.Atan2(x, y);
}

Is producing this disassembly:

001f0078 55              push    ebp
001f0079 8bec            mov     ebp,esp
001f007b dd05a0001f00    fld     qword ptr ds:[1F00A0h]
001f0081 83ec08          sub     esp,8
001f0084 dd1c24          fstp    qword ptr [esp]
001f0087 dd05a8001f00    fld     qword ptr ds:[1F00A8h]
001f008d 83ec08          sub     esp,8
001f0090 dd1c24          fstp    qword ptr [esp]
001f0093 e86e9ba66f      call    clr!GetHashFromBlob+0x94e09 (6fc59c06) (System.Math.Atan2(Double, Double), mdToken: 06000de7)
001f0098 ddd8            fstp    st(0)
001f009a 5d              pop     ebp
001f009b c3              ret

Even if you're not an x86 guru, you'll notice something odd in there: there's a call to System.Math.Atan2. As in a function call.

But there's actually an x86 opcode that would do that: FPATAN

Why is the JITer calling a function when there's an actual assembly instruction to do the operation? I thought that System.Math was basically a wrapper for native assembly instructions. Most of the operations in there have direct assembly opcodes. But that's apparently not the case?

Does anyone have any information on why the JITer isn't/can't perform this rather obvious optimization?

like image 833
Jay Lemmon Avatar asked Apr 21 '13 07:04

Jay Lemmon


1 Answers

You can chase down the reason from this answer, it shows how these math functions are mapped by the jitter.

Which takes you to clr/src/classlibnative/float/comfloat.cpp, ComDouble::Atan2() function. Which explains the reason:

   // the intrinsic for Atan2 does not produce Nan for Atan2(+-inf,+-inf)
   if (IS_DBL_INFINITY(x) && IS_DBL_INFINITY(y)) {
       return(x / y);      // create a NaN
   }
   return (double) atan2(x, y);

So it is a workaround to fix FPU behavior that is not CLI compliant.

like image 162
Hans Passant Avatar answered Oct 11 '22 15:10

Hans Passant