2013-04-21 4 views
6

C#でいくつかの数学コードを書いていますが、それはリリースで最適化されたx86用にコンパイルする必要があり、私はwindbgで逆アセンブリを見ています。それは通常かなり良いです、しばしば私ができるよりも優れたアセンブリを書いています(私はすべてアセンブリでうまくいくわけではありませんが、そこに行く)。Math.Atan2とFPATAN

しかし、私はこの機能気づいた:

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

は、この分解を生産している:

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 

あなたは、x86の第一人者でない方でも、あなたが奇妙な何かに気付くでしょうそこには:System.Math.Atan2への呼び出しがあります。関数呼び出しの場合と同じです。

しかし、それを行うだろうx86のオペコードは実際にあります:操作を行うには、実際のアセンブリ命令があるときFPATAN

はなぜJITer関数を呼び出していますか?私はSystem.Mathが基本的にネイティブアセンブリ命令のラッパーであると考えました。そこにある操作のほとんどは直接アセンブリのオペコードを持っています。しかし、それは明らかにそうではありませんか?

JITerがこの明白な最適化を実行できない/できない理由に関する情報をお持ちの人はいませんか?

+1

私がGoogleのバグをfpatan'とすると、いくつかのプロセッサモデルでいくつかの結果が得られるので、 'Math.Atan2'がこれらのバグを回避して動作し、' Math.Atan'に置き換えられました。私は本当に確信していませんが、おそらくそれは探す方向になる可能性がありますか?良い質問。 – Silvermind

+0

"JITerがなぜこの明白な最適化を実行できないのか/実行できないのかについての情報は誰にもありますか?"私は問題のJITについては言いませんが、複数のプラットフォームで 'atan2' FPATAN命令を呼び出すことは明白な*悲観化*となります.FPATANは、関数呼び出しのオーバーヘッドを含めても、優れたソフトウェア実装よりもはるかに低速です(150-300サイクル対50-100サイクル、 –

答えて

5

this answerから理由を取り除くことができます。これは、これらの数学関数がジッタによってどのようにマッピングされるかを示しています。

これは、clr/src/classlibnative/float/comfloat.cpp、ComDouble :: Atan2()関数を表示します。理由を説明します:

// 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); 

したがって、CLIに準拠していないFPUの動作を修正するための回避策です。

+0

私はここに何かが固定されているとは言いませんが、それは修理者ではなくアダプタです –

+0

ああ、元気ですが、それは必ずしも理由ではないと思います。たとえば、COMDouble :: Logは文字通りintrinsic logを呼び出します。ecall.cppからは、sin、cos、sqrt、round、およびabsのみが直接マップされています。 intrinsicsに。 –

+0

ComDouble :: ExpとLogのコードもまたコメントで見ることができます。 SSE2バージョンの速度が遅すぎ、Expにも同様のドメイン問題があることに注意してください。彼らは** intriicを使わず**、これらの関数のCRTバージョンを呼び出します。インテルの手作りのアセンブリコード。かなり明白なコメントよりも優れた理論を持っているなら、それを聞いて欲しいです。 –

関連する問題