[過去ログ] Visual Studio 2008 Part 22 (314レス)
上下前次1-新
抽出解除 必死チェッカー(本家) (べ) 自ID レス栞 あぼーん
このスレッドは過去ログ倉庫に格納されています。
次スレ検索 歴削→次スレ 栞削→次スレ 過去ログメニュー
210: 2018/09/16(日)12:52 ID:haV9TZ8e(1/12) AAS
>>209
興味深い結果だ。
211(1): 2018/09/16(日)13:21 ID:haV9TZ8e(2/12) AAS
>>209
>命令自体は rdtsc と同じで非同期に実行されている雰囲気だが、
>rdtsc命令の注意書きにある「シリアル化命令ではない」という但し書きが無く、状況は不明。
>正直、正しく読み出せているか怪しい。(あてにならない)
インラインアセンブラを使わずに、
_control87(), _controlfp() : Get and set the floating-point control word.
unsigned int _control87( unsigned int new, unsigned int mask );
unsigned int _controlfp( unsigned int new, unsigned int mask );
を使ってみたらどうなる?
215: 2018/09/16(日)13:53 ID:haV9TZ8e(3/12) AAS
>>213
なるほど、全く別の2つの理由で、精度が変わっている可能性(というより多分、確実)があると。
それは以下の2つ:
1. Debug版とRelease版では、最適化の結果、x87 FPU命令の使われ方が変わる。
x87では、メモリに書き戻さずに st(0)〜st(7)レジスタに入っている途中では、
拡張倍精度の80BITで計算されるが、書き戻すとdoubleの場合でも64BITに丸め
られる。なるべくメモリに書き戻さずにレジスタった方が高速なので、Release版
では、80BITで計算される「期間」が多くなる。そのため、Debug版とRelese版では
結果が僅かに違ってくる。
2. fpu control word が違っていて、st(0)〜st(7)に入っていても、計算が
80BITか、64BIT、32BITのどれで計算されるか異なったり、丸め方が四捨五入
か、正負二種類の方向の切り捨てなどが変わっている。
そして、IDEから起動した場合と、コマンドラインから起動した場合で結果が違う
のは、「2.」の理由によるものではないかと。そして、実際に、インラインアセンブラ
で fpu control word を読み取ってみると、不安定な値が読み出されたと。
216: 2018/09/16(日)13:58 ID:haV9TZ8e(4/12) AAS
まず、
__asm{
fnstcw [cw];
}
ではなく、_control87() を使ってみて欲しい。
インラインアセンブラは、独立した *.asm で書くより危険な場合が
あるかも知れないので。特にC関数の引数、今の場合は、「cw」を
インライン・アセンブラで用いた場合、正しいコードが出ているかどうか
は注意が必要。
217: 2018/09/16(日)14:05 ID:haV9TZ8e(5/12) AAS
>>208
よく見ると、それは、かなり複雑な事情が絡みそうなコード。
以下のようにした方が安心。なお、「cw」という短すぎる引数名
も長年のプログラミング経験からすると、インラインアセンブラでは
怖い。また、
TTTT reg,引数名
や
TTTT 引数名
は大丈夫でも、
TTTT reg,[引数名]
や
TTTT [引数名]
は1命令では不可能な事をコンパイラに指示している事になるので
ちょっと怖い。間接の間接、つまり、[[ebp+8]]みたいな事を要求
しているが、そんなオペランドが使えるアセンブリ命令はx86/x64
では存在しないので。
#pragma unmanaged
inline void fpu_getcw(unsigned short *pCW) {
__asm{
mov edx,pCW
fnstcw [edx];
}
}
#pragma managed
218(4): 2018/09/16(日)14:17 ID:haV9TZ8e(6/12) AAS
あ、後、インライン・アセンブラで実験する場合は、関数名の inline は
「取った」方がいい。つまり、以下の方が安心:
#pragma unmanaged
void fpu_getcw(unsigned short *pCW) {
__asm{
mov edx,pCW
fnstcw [edx];
}
}
#pragma managed
221(1): 2018/09/16(日)15:40 ID:haV9TZ8e(7/12) AAS
>>219
ホントだ。/MDだと、Runtime Library として DLL のものを使ってしまう。
これは、今回の現象に非常に重要な影響を与えているかも知れない。
222: 2018/09/16(日)15:42 ID:haV9TZ8e(8/12) AAS
>>220
いや、まだまだ興味深い。
ここで終わらせずにもっと徹底して追及すべきだ。
227(1): 2018/09/16(日)16:02 ID:haV9TZ8e(9/12) AAS
>>225
をを。やはり、ある意味ではVCが間違ったアセンブリコードを出していたよ。
それだと、
fnstcw [EBP+08]
という意味になってしまって、
fnstcw pCW
の意味になっている。つまり:
pCW = control_word;
あなたが、やりたいのは、
*pCW = control_word;
だったのだから、アセンブリ・コードが間違ってる。
あなたが指示したのは、
fnstcw [pCW]
だった。実際に生成されたコードは、
fnstcw pCW
だった。
VC のインラインアセンブラは、エラーも出さずに間違ったコードを
出すことが証明された。
これと、精度が不安定な問題とは全く別ではあるけれど。
229(1): 2018/09/16(日)16:11 ID:haV9TZ8e(10/12) AAS
>>225
>正直、/7の意味が分からないのだが、
ModRM とは、
mod reg r/m
76 543 210
のようなオペランドを指しているのだけど、/7 は、regの部分を2進数の111、
10進数の「7」にするという意味。このタイプのマシン語は、
mod ttt r/m
とも書かれる。tttの部分は、命令の主幹部分(ニモニック部分)によって変わる。
普通は、レジスタ番号を入れるところに、命令の種類を表す3BITの値を入れる
仕様になっている。
あなたがインラインアセンブラでVCに出させたかったコードは、意味的には、
fnstcw [[EBP+08]]
なのだが、[ ] を二重にしたようなそんなx86/x64命令は存在しないので
VC がエラーも出さずに勝手に一重の
fnstcw [EBP+08]
にしてしまった、という事。本当は、
mov edx,[EBP+08]
fnstcw [edx]
というコードにしなくてはならなかったのに、VCがある意味では間違った。
これが、単独の *.asm ではなく、VC の asm {・・・} が危険な理由。
VC の asm は特に危険。
230(1): 2018/09/16(日)16:17 ID:haV9TZ8e(11/12) AAS
>>228
>ただし>>191の再現コードで『不定スタック領域』を掴んでいるわけもなく、
>一応IDE起動とコマンドプロンプト起動での挙動の違いを再現出来ているわけだから、
>これだけが問題ではないのも事実だ。
そうだよ。精度が変わるのはあなたの間違いではない。スタック領域が0クリア
されようがれまいが、あなたのコード自体には特に不安定さはない。
非初期化領域を参照しているコードは見当たらないし。
231(3): 2018/09/16(日)16:20 ID:haV9TZ8e(12/12) AAS
逆アセンブラ結果を見てないで言うけど、もし、sqrt() が call文で関数呼び出し
されているんだったら、そこで精度の違いが出てるかもしれない。
上下前次1-新書関写板覧索設栞歴
スレ情報 赤レス抽出 画像レス抽出 歴の未読スレ AAサムネイル
ぬこの手 ぬこTOP 0.028s