アセンブラに関するマジ質問だけど

このエントリーをはてなブックマークに追加
1デフォルトの名無しさん
今、半透明ってやつをやってるんだけど。256色の。
どうにも速度が出ないんだよね・・・・
下に俺のソースの抜粋書くから、
わかる人は教えてくれないかな・・・?
2デフォルトの名無しさん:2001/07/15(日) 18:52
あらかじめ、半透明のカラーテーブル(256*256)を
64KB境界に合わせておいて、
mov EBX, [Table]
というふうにEBXに入れておく。
で、下が<半透明書き込み部分>
mov BL, [ESI] //転送元をBLに
mov BH, [EDI] //転送先のBHに
mov AL, [EBX] //書き込む色をALに
mov [EDI],AL
inc EDI
あとは横×縦のループでこれを囲む。
3デフォルトの名無しさん:2001/07/15(日) 18:54
アセンブラスレなら、既にいくつかあっただろう・・
4デフォルトの名無しさん:2001/07/15(日) 19:00
ちなみに、かかるクロック数は、上から
1,1,5,2、1。
mov AL, [EBX] でストールが発生しちゃってるんだよね・・・
かといって、普通にADD使うと遅そうだし。
5デフォルトの名無しさん:2001/07/15(日) 19:03
スマン。新スレ立てることはなかったな。
上のほう見てなかったんで。

もしわかる人いたらsageでいいから頼む・・・
6デフォルトの名無しさん:2001/07/15(日) 19:05
パーシャルレジスタストールかな
データを3個くらい並列処理したら?
7デフォルトの名無しさん:2001/07/15(日) 19:06
>>2
これってもろパーシャルレジスタストールじゃない?
P6系ではBLとBHを別々に書き込んで、EBXで合わせて使うと
ストールが発生したはず。
そのまま素直にシフト+加算で計算した方がいいよ。
87:2001/07/15(日) 19:07
ダブった。
9デフォルトの名無しさん:2001/07/15(日) 19:07
なるほど・・・・今、調べてきてみた。
下位だけ書き換えちゃいけなかったのね。
10デフォルトの名無しさん:2001/07/15(日) 19:09
>>6
>>7
どうもありがとう。
並列は、ループでECX,EDX使ってるから
ちょっと無理そう。(EDI,ESIは各矩形のポインタ)
ADD+シフトでやってみるよ。
11デフォルトの名無しさん:2001/07/15(日) 19:22
でも、

普通にシフトと足し算でやるにしても
結局下位8にロードして、左8シフト。さらに下位8にロードして
ポインタを足すわけでしょう?

結局このストールがおきるんじゃないのかな?
12デフォルトの名無しさん:2001/07/15(日) 19:49
実行結果。
mov EBX, [ESI]
mov EAX, [EDI]
and EBX, 255
and EAX, 255
shl EAX, 8
add EBX, tbl
add EBX, EAX
mov AL, [EBX]
mov [EDI],AL
inc EDI
inc ESI
inc EDX
というふうに修正したら、
9クロックから6クロックまであがったよ。
まだまだ実用的じゃないみたいだけど大きな進歩だね。
本当にありがとう。
13デフォルトの名無しさん:2001/07/15(日) 19:51
スマ。間違い。上のは8クロックのソースだ。

これが6。
mov EBX, [ESI]
mov EAX, [EDI]
and EBX, 255
and EAX, 255
shl EAX, 8
add EBX, cll
add EBX, EAX
inc EDI
inc ESI
inc EDX
mov AL, [EBX]
mov [EDI-1],AL
14デフォルトの名無しさん:2001/07/15(日) 20:06
>>11
パーシャルレジスタストールはP6のアウトオブオーダー実行コアの
命令スケジューラの制限じゃないかな?
パーシャルレジスタアクセスを行うとP6の命令スケジューラがマヒするんだと思う。
Pentium4ではパーシャルレジスタストールは無いらしい。
15デフォルトの名無しさん:2001/07/15(日) 20:13
>>13
mov EBX, [ESI]
mov EAX, [EDI]
and EBX, 255
and EAX, 255

movzx EBX, byte ptr [ESI]
movzx EAX, byte ptr [EDI]
でいいんじゃないかな。
16デフォルトの名無しさん:2001/07/15(日) 20:33
情報ありがとう!

>>14
なるほどね・・・・
てことは、Pentium4では、最初のが最速になるってことか。
本当に高速化を目指すならCPUごとに条件分岐すれば一番なのか・・・

>>15
おっと、盲点・・・・・恥ずかしい所を見せたか(^^;
17デフォルトの名無しさん:2001/07/15(日) 20:49
15の修正をしたところ、なんとか5クロック・・・・
というか、もうこれ以上はできない気がする。
できて4だろうが、それでも実用には向かない。
なぜだろう?

暇な人がいたら、でいいんだが
以下に半透明部分の全ソースを書くので
問題点があったら教えてくれないかな?
ずうずうしいとは思うんだが、もしできたら頼みたい・・・



 _asm{
  mov EDI, dat1 //EDIに転送元のポインタ(左上の点)
  mov ESI, dat2 //ESIに転送先のポインタ(左上の点)

  add EDI, Dot1 //EDIを転送開始点までずらす(X+Y*WIDTHを足す)
  add ESI, Dot2 //ESIを転送開始点までずらす(X+Y*WIDTHを足す)

  mov EBX, tbl //加算テーブル開始ポインタ



 // 外側ループ開始
  mov ECX, 0  // ループカウンタ(Y)
FOR_START_Y:
  push EDI //EDI退避
  push ESI //ESI退避
 // 内側ループ開始
  mov EDX, 0  // ループカウンタ(X)
  FOR_START_X:
  movzx EBX, byte ptr [ESI]
  movzx EAX, byte ptr [EDI]
  shl EAX, 8
  add EBX, tbl
  add EBX, EAX
  inc EDI
  inc ESI
  inc EDX //Xカウンタのインクリメント
  mov AL, [EBX]
  mov [EDI-1],AL
  cmp EDX, Width //横幅
  jl FOR_START_X
 // 内側ループ終了
  pop ESI //ESI復旧
  pop EDI //EDI復旧
  add EDI, W1
  add ESI, W2
  inc ECX //Yカウンタのインクリメント
  cmp ECX, Height //縦幅
  jl FOR_START_Y
 // 外側ループ終了
  }
18デフォルトの名無しさん:2001/07/15(日) 20:57
cll が定数ならば。


xor ebx, ebx
mov bl, byte ptr [ESI]
xor eax, eax
mov ah, byte ptr [EDI]
inc EDI
lea ebx, [cll + eax + ebx]
inc ESI
mov AL, [EBX]
inc EDX
mov [EDI-1],AL


で 5。
19デフォルトの名無しさん:2001/07/15(日) 21:03
とりあえず、ループ展開しとけ。
byte 単位でメモリアクセスしているのを dword 単位のアクセスにできるだろう。
20デフォルトの名無しさん:2001/07/15(日) 21:15
ばっかみたい!
DirectXならハードウェアで半透明やってくれるじゃん。
21デフォルトの名無しさん:2001/07/15(日) 21:16
クロックが8とか6とか意っているけれど、
何で計測しているのですか?
22>16:2001/07/15(日) 21:30
CPU 毎にインストールするバイナリを変える、だろ。
23デフォルトの名無しさん:2001/07/15(日) 21:31
>>20

煽りにしてもベタでつまらんな。
24sage:2001/07/15(日) 21:36
push EDI //EDI退避
push ESI //ESI退避

pop ESI //ESI復旧
pop EDI //EDI復旧

上のペアになる命令は要らないんじゃん?
W1とW2からあらかじめWidthを引いておけば。

mov EDX, 0  // ループカウンタ(X)

cmp EDX, Width //横幅

これとかも
mov EDX, Width

test EDX, EDX
としたほうが大抵速い。

せめて
xor EDX, EDX  // ループカウンタ(X)

cmp EDX, Width //横幅
としよう。
x86で、レジスタを0クリアするのに0を代入するか、普通?

mov [EDI-1],AL
これもあんまり良くないかも。
キャッシュを管理しているOSだと、
ライトキャッシュ効かなくなって遅くなることあるよ。
25sage:2001/07/15(日) 21:41
↑追加修正

当然気づいたとは思うけど、

mov EDX, 0  // ループカウンタ(X)

inc EDX //Xカウンタのインクリメント

cmp EDX, Width //横幅



mov EDX, Width  // ループカウンタ(X)

dec EDX //Xカウンタのインクリメント
^^^
test EDX, EDX

としてね。
ついでに言えば、testいらねーや。

mov AL, [EBX]
mov [EDI],AL
dec EDX //Xカウンタのインクリメント
jnz FOR_START_X
として。

つーかIAマニュアル読め。
26デフォルトの名無しさん:2001/07/15(日) 21:42
情報その他ありがとう!

>>18
なるほど。勉強になる・・・・
まともにうごかないのはcllがポインタだからかな?

>>19
ループの展開?
4ドット同時に処理せよということかな?

>>20
DIRECT3Dならね・・・

>>21
ネットで見つけた、誰かのプログラムなんだけど
どうも不安定っぽい。

>>22
そうだね(^^;
27デフォルトの名無しさん:2001/07/15(日) 22:25
>>24
>>25
有力な情報ありがとう。
やはり自分はまだまだ未熟だな・・・
やっぱり問題はループにあったのか。
cp+jlって意外と遅かったのね。

とりあえず、現時点のことを全部やったらFPSが52まで出るようになったよ。
みんなありがとう。
28名無しだよもん:2001/07/15(日) 23:21
testでジャンプするよりも
JECXZを使えばもっとはやいんじゃないの?
29名無しだよもん:2001/07/15(日) 23:21
スマン。JECXZじゃなくて、LOOPな
30デフォルトの名無しさん:2001/07/15(日) 23:38
ってことは。
今のところ、これが最高速?
もうこれ以上はあがらないのかな?



  mov EDI, dat1
  mov ESI, dat2

  add EDI, Dot1
  add ESI, Dot2

  mov EBX, tbl

 // 外側ループ
  mov ECX, Height // ループカウンタ(y)
FOR_START_Y:
 // 内側ループ
  mov EDX, Width // ループカウンタ(x)
FOR_START_X:
  //**処理**
  movzx EBX, byte ptr [ESI]
  movzx EAX, byte ptr [EDI]
  shl EAX, 8
  add EBX, tbl
  add EBX, EAX
  inc ESI
  mov AL, [EBX]
  mov [EDI],AL
  inc EDI
  dec EDX // Xカウンタのデクリメント
  jnz FOR_START_X
// 内側ループ終了
  add EDI, W1
  add ESI, W2
  dec ECX // Yカウンタのデクリメント
  test ECX,ECX
  jnz FOR_START_Y
// 外側ループ終了
31デフォルトの名無しさん:2001/07/15(日) 23:50
>>29
LOOPは複雑命令だから遅い。
32デフォルトの名無しさん:2001/07/15(日) 23:57
ってことは、LOOPはあるだけ無意味ってことなのか(w
33shige:2001/07/16(月) 00:59
今田にアセンブラなんてやってる奴いるんだな。
34デフォルトの名無しさん:2001/07/16(月) 01:20
何人かがアセンブラで最適化した分の利益を,我々は使わせていただいているんだ。
ってことに気付け。
35デフォルトの名無しさん:2001/07/16(月) 01:23
>>30
てか、これでもう最適なのか?
順番変えれば、ペアリングとかできそうじゃない?
36デフォルトの名無しさん:2001/07/16(月) 01:30
くそぉ
ネタにネタレスしてやるっ!!!!
>>33
Perlででもアルファブレンディングのルーチン書いて
死んでやがれヴォケ
37デフォルトの名無しさん:2001/07/16(月) 01:37
>>33
まあ普通は無駄だけど、MMXとかSIMD使う分には価値があるよ。
38shige:2001/07/16(月) 01:52
>>36
ハァ?何で俺がPerlみたいな糞言語やらなきゃならねーんだよ。
Ruby以外の言語は全部糞だっていつも言ってるだろヴォケ。
39デフォルトの名無しさん:2001/07/16(月) 02:20
有意義なスレだと思ったんだが、結局はこうか。
40デフォルトの名無しさん:2001/07/16(月) 02:26
>>30
最適ではない。
4136:2001/07/16(月) 02:32
>>38
悪かった。わざと言ったんだ。
じゃあ言い直すぜ!

Rubyででもアルファブレンディングのルーチン書いて
死んでやがれヴォケ
42デフォルトの名無しさん:2001/07/16(月) 02:37
フリーでソース付きの8086〜Pentium向けのアセンブラってありませんか?
あんまり大きくない奴で。
43デフォルトの名無しさん:2001/07/16(月) 02:38
あんまり大きくない奴で。 <サイズが。
44#6411:2001/07/16(月) 02:45
素朴なギモンだが、ターゲットがDirectDrawで、
出力先はフレームバッファだったりしないかな?
だとすると、抜本的な高速化は別の方法があると思われ。

ここ2年DirectX触れてないから、用語忘れた。…鬱だ…
451:2001/07/16(月) 03:08
>>4
本当?
今回は、LOCKを避けるために配列変数から配列変数への転送だけど
それについてはちょっと興味あるな。
なんせ、LOCK使うと遅くなるからサーフェスはほとんどつかわないつもりだったんで。
4636:2001/07/16(月) 03:21
>>42
nasm
47いつでもどこでも名無しさん:2001/07/16(月) 06:46
>>30
何で1バイトづつやってるの?
48デフォルトの名無しさん:2001/07/16(月) 07:30
>>26
>>21
>ネットで見つけた、誰かのプログラムなんだけど
>どうも不安定っぽい。
計測プログラムが気になる。URLキボン。
49デフォルトの名無しさん:2001/07/16(月) 07:40
>>47
最適化前だから。
50デフォルトの名無しさん:2001/07/16(月) 07:50
>>2の64KByte境界にあわせるってあるけど、こんなことってできるの?
511:2001/07/16(月) 08:30
>>47
>>49
レジスタももう埋まってて使えないし
どうやって並行処理するの?
MMX使うとかしかないのかな?

>>50
unsigned char* test;
unsigned char dummy[256*256*2];
test = (unsigned char *) (((unsigned)dummy + 65535) & (-65536))
っていう方法で。もしかしてちと強引なのかな?
521:2001/07/16(月) 08:32
>>48
ttp://www.yo.rim.or.jp/~sawara/opt/jk9905.html

WatcomC用ってなってたから、VC++にちょっと改造したけど。
53デフォルトの名無しさん:2001/07/16(月) 09:03
54デフォルトの名無しさん:2001/07/16(月) 10:25
何クロックとかって懐かしいね。でも、クロック計算できるのはPentiumまでよ。
P6以降は、μOP命令に変換されて、空いているスロットを使ってOOO実行とか
しちゃうから、クロックの計算は出来ないでしょう。
#V-Tuneでも、クロックは出ないはず。

>>28
Loopは、今や遅い命令です。

dec ecx
jnz @@@

の方が速いです(ただしP6の話。AMDでは使った方が速い)
また、P6はフラグストールとかって面倒なもんがあるんで、
cmpして判定しないと逆に遅くなったりします。

>>30
あとは、Loop Unrollして、Incとかはなるべく[esi + 01]とかに置き換えた方が良いよ。
55デフォルトの名無しさん:2001/07/16(月) 11:59
勉強になるのでage

最適化好きな人にはここがおすすめだよ。
ttp://homepage1.nifty.com/herumi/adv/adv40.html
561:2001/07/16(月) 13:23
>>54
なるほどね。だからクロック数が不安定だったのね。
数値が実行ごとにずれたりしてたから。
Loop Unrollって?
あと、Incなしで [esi + xx]のほうが速いんだ。
上にそっちだと遅いって人がいたけど、マシンによるのかな?

>>53
>>55
情報サンクス。
今から印刷してじっくりと見てみるよ。
57デフォルトの名無しさん:2001/07/16(月) 14:18
inc esiよりlea esi,[esi+1]をペアリングの空きに突っ込む方が吉
leaはフラグが変わらんから分岐の直前でもいいぞ
58デフォルトの名無しさん:2001/07/16(月) 15:55
>>57
そうだね。
それより
>>30
で気になるのが、movzxって遅くなかったっけ?
xor eax, eax
mov eax, byte ptr[edi]
としてペアリングした方が大抵速くなかったっけ?
59デフォルトの名無しさん:2001/07/16(月) 16:02
>>58
どうでもいいつっこみだけど
xor eax, eax
mov al, byte ptr[edi] ね。

おそいっていうかmovzxやmovsxはペアリングができないんだよ。
xorとmovに分解すればペアリングできる機会が増えるってことで。

いつ出るかなーと思っていたがなかなか出ないので
リンクage
http://www.csl.sony.co.jp/person/fnami/pentopt.htm
http://www.csl.sony.co.jp/person/fnami/asm.htm
60デフォルトの名無しさん:2001/07/16(月) 16:02
・lea 命令の使用
多くの場合、lea 命令、またはlea、add、sub、およびshift 命令のシーケンスを定数乗算命令
に代えて使用することができる。Pentium II およびPentium III プロセッサ用に設計されたコードを
最適化するには、整数乗算命令を使用する。lea 命令は、3 つまたは4 つのオペランドを取る加算
命令として使用できることがある。次に例を示す。
lea ecx, [eax+ebx+4+a]
このようにlea 命令を使用することで、複数の算術命令のオペランドでレジスタが占有されること
を避け、レジスタが不要に使われるのを防ぐことができる。
Pentium II およびPentium III プロセッサでは、lea 命令とshift 命令は、どちらも1 サイクルで実
行される単一µop 命令である。しかし、このレイテンシの短さは、将来の使用上でも保たれるかど
うかはわからない。
最適なブレンデッド・コードを得るためには、shift 命令を2 つ以上のadd 命令に置き換えると
よい。これは、この命令のレイテンシがすべての実装面で短いとは限らないからである。

・複雑な命令
一般に4 つよりも多くのµop を持ち、デコードに複数のサイクルが必要な複雑な命令( たとえば
enter、leave、loop) の使用を避ける。代わりに、単純な命令のシーケンスを使用すること。

・8/16 ビットのオペランド
Pentium II およびPentium III プロセッサでは、同じレジスタの排他的論理和をとり、レジスタの
リアがそのレジスタの以前の値に依存しないことを認識する機能を備えている。さらに、上記
コード・シーケンスでのパーシャル・ストールを回避する機能も備えている。詳細については
「パーシャル・レジスタ・ストール」の節を参照のこと。
Pentium II およびPentium III プロセッサでは、パーシャル・ストールの発生を抑えるために、movzx
命令のパフォーマンス向上が図られている。これらのプロセッサ向けのコーディングでは、movzx
命令を使用するとよい。
61デフォルトの名無しさん:2001/07/16(月) 16:48
今はP6系の最適化をしてるんでしょ?
なんでP5系のペアリングの話が出てくるんだ?
今時P5最適化なんてナンセンスじゃない?

Loop Unrollして、Incを使わず [esi + 1]で処理するというのは
依存性チェーンを断ち切って、P6のOOO実行性能を高めるっていう話でしょ?
62デフォルトの名無しさん:2001/07/16(月) 17:00
あと、P6系の最適化リファレンスマニュアルはこっちね。
http://www.intel.co.jp/jp/developer/design/pentiumIII/manuals/index.htm
これを読めばほとんど全部書いてある。ここで人に聞くより、
まずはこれを全部読むことから始めた方が近道だよ。
63デフォルトの名無しさん:2001/07/16(月) 18:01
>今はP6系の最適化をしてるんでしょ?
あ、そうだったのか

> なんでP5系のペアリングの話が出てくるんだ?
>今時P5最適化なんてナンセンスじゃない?
たしかにな(笑)
64デフォルトの名無しさん:2001/07/16(月) 18:49
現在のメインストリームは、P6なので、ターゲットを
P6にした方が良いと思うよ。
movzx, movsxは、P6では1μOP。がんがん使いましょう。
あと、最適化マニュアル読めばわかるけど、命令のデコーダが
1Clockで3つの命令をデコードできるんだけど、最初のデコーダのみが
4μOPまでの命令をデコードできて、残りの2つのデコーダは1μOPまで
(要するに超単純な命令)しかでコードできないから、なるべく
μOP命令数で、4-1-1になるように命令を配置した方がいいよ。
なるべくRSを一杯にしといた方が有利だからね > P6
65デフォルトの名無しさん:2001/07/16(月) 19:42
P6の整数演算ユニットは2個だぞ
シフトのレイテンシは大きいぞ
油断大敵!
66デフォルトの名無しさん:2001/07/16(月) 19:45
P6のシフトのレイテンシが大きい?また嘘ばっかり。
67デフォルトの名無しさん:2001/07/17(火) 00:41
Loop Unrollって何?
68デフォルトの名無しさん:2001/07/17(火) 00:51
>>67
>>62のアーキテクチャ最適化リファレンス・マニュアル読んだか?
69デフォルトの名無しさん:2001/07/17(火) 01:44
pdfをテキストかhtmlに変換するツール知らない?
701:2001/07/17(火) 03:33
おお、どんどん有力な情報が。
ようやくアンロールが理解できたよ。
いくつくらいに展開すりゃいいんだろ。
8?

>>64
あー、だから3つの命令でも例のプログラムで1クロックって出たり
したのか・・・・・納得。バグだと思ってたよ。
4−1−1ね。やってみる。ペアリングとかはもう気にする時代じゃないんだね。
71デフォルトの名無しさん:2001/07/17(火) 05:45
>>P6系所有者
2のコードだけど、マニュアルを読む限り、

xor EBX,EBX
mov EDX, [Table]
 :
 :
mov BL, [ESI]
mov BH, [EDI]
mov AL, [EDX+EBX]
mov [EDI],AL
inc EDI

にすれば、パーシャルレジスタストールしないで、
ループ出来そうなんだけど、どうなの?
72デフォルトの名無しさん:2001/07/17(火) 07:43
>>71
mov BH, [EDI]
の行がなければストールしない。
この行があるからストールする。
73デフォルトの名無しさん :2001/07/17(火) 07:56
>>51
EBPは?
74デフォルトの名無しさん:2001/07/17(火) 08:23
こういうのはだめかい?

  mov EAX, [EDI]
  movzx EBX, byte ptr [ESI]
  add EBX, tbl
  XLATB
  ror EAX,8

  movzx EBX, byte ptr [ESI+1]
  add EBX, tbl
  XLATB
  ror EAX,8

  movzx EBX, byte ptr [ESI+2]
  add EBX, tbl
  XLATB
  ror EAX,8

  movzx EBX, byte ptr [ESI+3]
  add EBX, tbl
  XLATB
  ror EAX,8
  LEA ESI,[ESI+4]
  LEA EDI,[EDI+4]
  mov [EDI],EAX
75デフォルトの名無しさん:2001/07/17(火) 08:41
もう一息!
76デフォルトの名無しさん:2001/07/17(火) 08:46
ありゃ、EBXを8bitシフトするの忘れてる

それから ECX,,EDXをループカウンタに使うのは勿体ないよ
ECXは無条件にスタック上で処理すればいいし
EDXも内側の処理が短くできるならスタック上に取った方がいいよ

XLATBは パーシャルレジスタストールの対象になると思うから
この2つのレジスタを参戦させて
  mov EAX, [EDI]
  mov EBX, [ESI]
  ror EBX,8
  MOV EDX,EAX
  SHLD EDX,EBX,8
  AND EDX,0xffff
  ADD EDX,tbl
  movzx ECX, byte ptr [EDX]
  SHRD EAX,ECX,8
  ror EBX,8
  MOV EDX,EAX
  SHLD EDX,EBX,8
  AND EDX,0xffff
  ADD EDX,tbl
  ・・・繰り返し・・
7776:2001/07/17(火) 08:51
それから、tblが固定アドレスなんだったら tbl[EDX] とか [EDX+tbl]と書いた方が
早くなる可能性がありそうな気がする 固定じゃないんだったらEBPを使ったらどう?
7876:2001/07/17(火) 08:54
さらに8bitで3:3:2とかのパレット固定だったら その場で計算させた方が速い場合もあるよ
79デフォルトの名無しさん:2001/07/17(火) 09:55
  push Width
FOR_START_X:
  movzx EDX, byte ptr [ESI]
  movzx EBX, byte ptr [ESI+1]

  movzx ECX, byte ptr [EDI]
  movzx EAX, byte ptr [EDI+1]
  shl EAX, 8
  shl ECX, 8
  add EBX, tbl
  add EDX, tbl
  LEA ESI,[ESI+2]
  add EBX, EAX
  add EDX, ECX
  mov AL, [EBX]
  mov AH, [EDX]
  mov [EDI ],AL
  mov [EDI+1],AH
  dec [ESP]; //スタックをカウンタに
  LEA EDI,[EDI+2]
  jnz FOR_START_X
  pop EAX;//読み捨て
80デフォルトの名無しさん :2001/07/17(火) 10:22
76の勝ち!
8164:2001/07/17(火) 10:35
せっかく書いたのに、改行が多すぎますって言われた。
82デフォルトの名無しさん:2001/07/17(火) 10:51
複数にわければOKじゃない?
831:2001/07/17(火) 11:10
みんなすげえなあ・・・・
最初、上のソースが何やってるかさっぱりだったよ。

とりあえず1行ずつ追っていって、なんとかどういう意味なのかわかったよ。

>>74
4つ平行か。
EAXをいちいち読むよりこっちのほうが早いんだ?

>>76
これはどうやってループにするの?
79のソースみたいにスタックを使えばいいのかな?
ためしにやってみたけど、なんか遅かった・・・おかしいな?

>>79
スタックを使ったカウンタのやり方サンクス〜
84デフォルトの名無しさん :2001/07/17(火) 11:17
8579:2001/07/17(火) 11:21
>>74 は XLATB 直後に ror EAX,8 がどうもパーシャルレジスタストール
  する可能性有り

>>76のコードは 4つ一度にロードしてるけど、
  EDXを連続して操作してるから思ったより
 早くないかもしれないね。

あ、でも>>79は push Width/2 に変えてね
8664:2001/07/17(火) 12:00
分割行きます。

mov ebx, table
mov esi, src_pixel
mov edi, dst_pixel

lopY:
mov ecx, nWidth
shr ecx, 2 // 4回Unroll
mov nDivided_Counter, ecx // Unroll用のループ回数
cmp ecx, 0 // P6ではフラグストールするのでcmpする
jz short modulo // 余った分の処理

lopX:
movzx eax, byte ptr [esi + 00] // 1 : src0 load
movzx edx, byte ptr [edi + 00] // 1 : dst0 load
shl eax, 8 // 1 : scaling(*256)

lea edx, [ebx + edx] // 1 : table + index
mov ecx, byte ptr [esi + 01] // 1 : src1 load
mov al, byte ptr [edx + eax] // 1 : table load

mov byte ptr [edi + 00], al // 2 : store0
shl ecx, 8 // 1 : scaling
movzx eax, byte ptr [edi + 01] // 1 : dst1 load

lea edx, [ebx + ecx] // 1 : table + scaler
mov ecx, byte ptr [esi + 02] // 1 : src2 load
mov al, byte ptr [edx + eax] // 1 : table load

mov byte ptr [edi + 01], al // 2 : store1
shl ecx, 8 // 1 : scaling
movzx eax, byte ptr [edi + 02] // 1 : dst2 load

lea edx, [ebx + ecx] // 1 : table + scaler
mov ecx, byte ptr [esi + 03] // 1 : src3 load
mov al, byte ptr [edx + eax] // 1 : table load

mov byte ptr [edi + 02], al // 2 : store2
shl ecx, 8 // 1 : scaling
movzx eax, byte ptr [edi + 03] // 1 : dst2 load

lea edx, [ebx + ecx] // 1 : table + scaler
add esi, 4 // 1 :
mov al, byte ptr [edx + eax] // 1 : table load

mov byte ptr [edi + 03], al // 2 : store3
add edi, 4 // 1
dec nDivided_Width // 2 : LoopCounter
jnz short lopX // 1
8764:2001/07/17(火) 12:01
後半いきます。

modulo:
mov ecx, nWidth // 横幅取得
and ecx, 3 // Unroll余り分

// Unrollで余った分だけやる
modulo_lopX:
movzx eax, byte ptr [esi]
movzx edx, byte ptr [edi]
shl eax, 8
lea edx, [ebx + edx]
add edx, eax
mov al, byte ptr [edx]
mov byte ptr [edi], al
inc esi
inc edi
dec ecx
jnz short modulo_lopX

// Y方向のポインタ計算はここでやって!
// テーブルの内容が連続しているならこれで良い
dec nHeight // ちょっと手抜き
jnz short lopY
8864:2001/07/17(火) 12:04
割と適当に書いて、動かしてないから、動かないかも(藁
コメント以下の数字:が、P6のμOP数です。
もっと詰められるけど、まぁこんな感じでUnrollして
4-1-1配置にすれば良いという参考までに。
あとは、ループの先頭を16Bytesにアラインする、
テーブルをキャッシュにプリロードする、
SSE使っていいなら、prefetch命令を最内周ループの
先頭に入れて、次のループ分をキャッシュに入れちゃうとか
まぁそんなところで。
89デフォルトの名無しさん:2001/07/17(火) 12:11
>>85
そうね。一見速そうに見える>>76のコードは実は遅い。
なぜかというと、上から下まで同一レジスタが生きているので処理順序を強制され、
アウトオブオーダー&レジスタリネームがほとんど生きない。

この半透明アルゴリズムでボトルネックはどこかというと、この
movzx ECX, byte ptr [EDX]
64KBのテーブルを読む部分。
64KBのテーブルをランダムにアクセスするので、1次キャッシュをミスする可能性が高く、
ここで処理が滞る事が多い。
だから、ここで処理が滞っても、アウトオブオーダーで次のドットを先に処理できるように、
コードを工夫した方がいい。
90デフォルトの名無しさん:2001/07/17(火) 14:01
みんな、もっとスタックフレームを使おうぜ。

今後はますます平行処理出来る事をCPUにどう知らせるかが高速化の
決め手になるんだからさ
91デフォルトの名無しさん:2001/07/17(火) 15:17
スタックアドレスの前後がレジスタに割り当てられるCPUがあるね
92デフォルトの名無しさん:2001/07/17(火) 16:23
>>88
>SSE使っていいなら、prefetch命令を最内周ループの
>先頭に入れて、次のループ分をキャッシュに入れちゃうとか

とりあえず、ダミーで最内周ループ先頭に
mov al,[esi+4]
mov al,[edi+4]
って入れちゃえばいいんじゃない?
実際に入れてみるとちょっと速くなるみたい。
93デフォルトの名無しさん :2001/07/17(火) 17:21
>>73
ESPもあるぞ
9464:2001/07/17(火) 17:35
>>92
P6の場合キャッシュ1ラインは32Bytesなので、32Bytes置きでOK。
よって、サイズにもよるけど、Yのループでやる方が良いかもね。
95デフォルトの名無しさん:2001/07/17(火) 17:43
既に6クロックで1ドット処理出来てるなら 640x480ドット処理しても
100Mのマシンでも1秒50フレームは処理出来るじゃないか

いったいなぜ不満が?
9679:2001/07/17(火) 17:56
そうか、そんなに早くなかったのか・・・・
昔は読み書き回数 減らせばそれだけ早くなった
んだけどなあ・・・というか最近最適化なんてやってないな
97#6411:2001/07/17(火) 19:01
漏れがDirectDrawで半透明処理やってたときは、
ターゲットがMMXなP55Cだったけど、いかに1次キャッシュの上で
処理を完結させるかがキモだったような気もしたり。
バリバリ半透明合成やっても、20fpsくらいは出てたぞ〜
VTuneのトライアル版にだいぶお世話になったがの。
98デフォルトの名無しさん:2001/07/17(火) 19:19
>>96
P6の場合、整数演算実行ポートとロード・ストア実行ポートが別々になっているので、
1次キャッシュにヒットするロード・ストアは有効に使った方がいい場合がある。
無理にレジスタのみで処理しようとすると、整数演算実行ポートばかりが飽和してしまい、
ロード・ストア実行ポートはガラ空きという、もったいない状況になる場合がある。
99デフォルトの名無しさん:2001/07/17(火) 20:03
半透明合成で20FPSってぜんぜん自慢にならん(´д`;)
ま、用途にもよるか。
# demoならOK。ADVゲームならOK。アクションなら×ってか。
10064:2001/07/17(火) 22:03
>>99
でもP55Cの時代だしね。
解像度にもよるけどまぁまぁなんじゃない?
101デフォルトの名無しさん:2001/07/17(火) 22:14
MMX命令とは使えばもっとはやくなるんじゃないの?
102デフォルトの名無しさん:2001/07/17(火) 22:38
>>101
MMXはテーブルにアクセスできないからね。
このアルゴリズムではMMXは使えない。
テーブルが簡単なものであれば、テーブルを使うのをやめて地道に計算→MMX化はできるけど、
テーブルが複雑なものであれば無理。
103デフォルトの名無しさん:2001/07/17(火) 22:38
パレットではどーにもならん>MMX
104デフォルトの名無しさん:2001/07/17(火) 22:52
L R1,0(,R1)
LH R0,0(,R1)
LTR R0,R0
BZ ABEND
BCTR R0,0
STC *+5
MVC PARMSTR(0),2(R1)

これを知っている人は"化石決定"です。
105デフォルトの名無しさん:2001/07/17(火) 23:17
TLCS-12A ってCPU 知ってる?
106デフォルトの名無しさん:2001/07/17(火) 23:34
P6では、この>>86-87のソースが最適化みたいね。
これ以上はないでしょう。
107#6411:2001/07/18(水) 00:20
>>99 ADVに使おうと思ってた。逆にアクション向けだったら
重いセル合成などやらない方針にしてたと思う。
ちなみに出力先サーフェスは16bit(ビット配置はさまざま)だった。
108デフォルトの名無しさん:2001/07/18(水) 06:01
16bitでアルファブレンドしてるんだけど
640x480x16で20fpsも出てくれません。
全画面ブレンドして60fpsは無理でしょうか?
ブレンドも50%固定でなく、0〜100%でやってます。
CPUは400MHzです。
109#6411:2001/07/18(水) 07:02
>>108 手で最適化してみたいのなら、下記から「最適化マニュアル」手繰ってちょ。
http://www.intel.co.jp/jp/developer/design/pentium/manuals/
アルファブレンドとかパッキングに関しては、下記から登録して、
Imageとかそのあたりを読み漁ってもらえれば。ただしぜんぶ英語。
http://developer.intel.com/software/idap/

漏れの経験では、P55C-266にて、640x480x16の
全画面クロスフェードが25fps超えてた。(DX5の時代)
当時のKlamath-266では、40fpsくらい逝ってた記憶も。
どうしても速くならなかったら、ソースの一部示せ。

なお、DirectDrawオンリーでなければ、最近のマシンでは60fps楽勝だ。
110#6411:2001/07/18(水) 07:08
ageとこ。
ちなみに、当時のK6-2でもまともな速さで動いてたけど、
MMX器が1つしかないK6とかCyrix 686MXでは、トホホな感じだった。
VTuneでPentium最適化にしてしまったからのー。
111デフォルトの名無しさん:2001/07/18(水) 07:18
>>106
やってる事が分かりやすいように、命令の順番を変えてませんし、
本当に早いか測ってませんが、ループの中身が、こんなのはどうですか?
P6のコストが、いまいち良く分からんので、自信はないけど、
P6に合わせて最適化すれば86のループよりは早くなりそうかと…。

(EBPはテーブル)
lopX:
mov eax, dwrod ptr [esi+000h]
mov ebx, dwrod ptr [edi+000h]
rol eax, 8
mov ecx, eax
mov edx, ebx
and eax, 000ff00ffh
and ebx, 0ff00ff00h
and ecx, 0ff00ff00h
and edx, 000ff00ffh
or ebx, eax
or ecx, edx
rol ebx, 8
movzx eax, cx
movzx edx, bx
shr ebx, 16
shr ecx, 16
mov al, byte ptr[ebp+eax]
mov bl, byte ptr[ebp+ebx]
mov cl, byte ptr[ebp+ecx]
mov dl, byte ptr[ebp+edx]
mov byte ptr[edi+000h], al
mov byte ptr[edi+001h], bl
mov byte ptr[edi+002h], cl
mov byte ptr[edi+003h], dl
add esi, 4
add edi, 4
dec nDivided_Width
jnz short lopX
112デフォルトの名無しさん:2001/07/18(水) 08:35
>>106
うーん、ちょっと見た限りでは>>86-87もいいけど
>>79 も同じくらいの速さは出るようにに思うんだがなあ
 特にAthlonだと 79の勝ちのように思う
113112:2001/07/18(水) 08:46
おお、>>111が Athlonではダントツの結果だね 79のさらに半分で計算出来る
さらに微妙な所を狙うなら後半のループの部分で
add はフラグが変化するから

LEA esi,[ esi+4]
mov al, byte ptr[ebp+eax]
mov bl, byte ptr[ebp+ebx]
mov cl, byte ptr[ebp+ecx]
mov dl, byte ptr[ebp+edx]
dec nDivided_Width
mov byte ptr[edi+000h], al
mov byte ptr[edi+001h], bl
mov byte ptr[edi+002h], cl
mov byte ptr[edi+003h], dl
LEA edi,[ edi+4]
jnz short lopX

と速めにJNZが使うフラグを確定させてやった方がいいかも
11464:2001/07/18(水) 10:25
>>113
decとjnzを離すとP6だとフラグストールしないか?
115112:2001/07/18(水) 10:51
>>114
 この場合間に入れた演算命令がLEAだけだから
>依存関係を解消するために必要以上に離れていると
>前の命令の結果は現在の命令側のμop が必要とし
>た時点で、もはやディスパッチ・バッファに残っていない
>可能性がある。
 だけど
>基本的な目安は、依存関係が解消されるだけの時間を
>取りながらも、バッファから結果データが失われるほど長
>時間ではない程度
だから、 LEA1個くらいなら大丈夫なんでは?
11676:2001/07/18(水) 11:03
>>111 方針は >>76と似てるけど、レジスタを巧くばらけて使ってるから速いんだな

半分って事は 、1ピクセル3クロック程度?

27命令が 12クロックか・・・
117デフォルトの名無しさん:2001/07/18(水) 11:37
>>113
Athlonだとそんなに>>111が速い?
うちのPentiumIIだと>>111より>>86の方が若干速いみたいよ。
118112:2001/07/18(水) 11:53
>>117 そうだね。キャッシュをヒットさせる条件で2.5倍くらい差が出たよ
Athlonは整数演算もアドレス演算もパイプラインが3つあるから途中の
同種命令が固まってあっても苦にならないんだろうね

PenII/IIIは整数演算ユニットは2つで、シフトは片方でしか実行出来ない
から、 それ用に命令の順番を変更してみたらどうよ?
119デフォルトの名無しさん:2001/07/18(水) 12:34
PenII/IIIは命令デコードの段階でパイプ詰まり起こしてます
120デフォルトの名無しさん:2001/07/18(水) 21:32
>>118
Athlonだと1ピクセル当たり何クロックで処理できるの?
121デフォルトの名無しさん:2001/07/19(木) 02:36
PenIIでの最適化ってどんなやつ?
2個ってことは、ペアリングとか?
122111:2001/07/19(木) 08:19
とりあえず、出来る限りチェーンを断ち切りましたが、
後半部分が、上手く動かない可能性が高いので、
論理和、シフト、ゼロ拡張付きロード、「add esi, 4」、
「sub nDivided_Width, 001h」の位置を適当に入れ替えてみたり、
前回のように、1バイトずつストアする方法に戻してみたりして下さい。

(今回もEBPはテーブル)
lopX:
mov edx, dwrod ptr [esi+000h]
mov ecx, 000ff00ffh
mov ebx, 0ff00ff00h
mov eax, dwrod ptr [edi+000h]
and ecx, edx
and edx, ebx
and ebx, eax
shl ecx, 8
and eax, 000ff00ffh
shr ebx, 8
or ecx, eax
or edx, ebx
movzx eax, cx
shr ecx, 16
add edi, 4
movzx ecx, byte ptr[ebp+ecx]
movzx ebx, dx
shr edx, 16
movzx ebx, byte ptr[ebp+ebx]
shl ecx, 16
movzx edx, byte ptr[ebp+edx]
shl ebx, 8
movzx eax, byte ptr[ebp+eax]
shl edx, 24
or ebx, ecx
or edx, eax
add esi, 4
or edx, ebx
sub nDivided_Width, 001h
mov byte ptr[edi-004h], edx
jnz short lopX
123112:2001/07/19(木) 08:55
>>122 コードが正しいとして、(dwrod は修正 byte ptrは取った)
Athlon で前回3.6クロック/ピクセルから 3.5クロック/ピクセルに改善されました
124デフォルトの名無しさん:2001/07/19(木) 11:39
PentiumIIで計測してみたら
1次キャッシュに完全にヒットさせた状態で
>>86 が3.55クロック/ピクセル
>>122 が3.75クロック/ピクセル
くらい。

640×480ピクセル、ピクセルデータランダム、テーブルデータランダムだと、
>>86 が11.66クロック/ピクセル
>>122 が11.76クロック/ピクセル
くらいだった(ビデオメモリに転送せず、メインメモリ上で処理した場合)。
125124:2001/07/19(木) 12:05
うちのPentiumIIでは次のような単純なコードが一番速かったよ。

mov edx, Width
lopX:
movzx ecx, byte ptr [esi]
shl ecx, 8
movzx eax, byte ptr [edi]
mov al, [tbl+eax+ecx]
mov [edi], al

movzx ecx, byte ptr [esi+1]
shl ecx, 8
movzx eax, byte ptr [edi+1]
mov al, [tbl+eax+ecx]
mov [edi+1], al

movzx ecx, byte ptr [esi+2]
shl ecx, 8
movzx eax, byte ptr [edi+2]
mov al, [tbl+eax+ecx]
mov [edi+2], al

movzx ecx, byte ptr [esi+3]
shl ecx, 8
movzx eax, byte ptr [edi+3]
mov al, [tbl+eax+ecx]
mov [edi+3], al

add esi, 4
add edi, 4

sub edx, 4
jne lopX
126デフォルトの名無しさん:2001/07/19(木) 12:46
やっぱ、分岐も投機実行するからフラグの心配は意味なしだ
127 :2001/07/19(木) 13:15
Winでマシン語プログラミングなんかできるのか?
「EXEファイルはOSは理解するがCPUは理解しない」
APIでしか交信できない
.dll
.h
.lib
.drv
.VxD
.sys
.ocx
128デフォルトの名無しさん:2001/07/19(木) 13:26
>>127
さぁ、どうなんだろうね?難しい質問だね。
答えが分かったら是非教えてね。
129#6411:2001/07/19(木) 15:58
>>128 禿げしく同意。難しい日本語の質問だね。
130111:2001/07/19(木) 16:26
>>123
どこかミスってましたか?(^^;;;
確認してなかったので、申し訳ないです。m(_ _)m
と言う訳で、またまた確認してませんが、P6用に修正しました。
マニュアルしか読んでないので、本当に早いのか疑問はありますが…。

ループの外は何も考えてないので、適当に、その外に吸収してやって下さい。

(またまたEBPがテーブル)

mov edx, 0ff00ff00h
and edx, dwrod ptr [ edi+000h ]
mov ebx, 0ff00ff00h
and ebx, dword ptr [ esi+000h ]
shr edx, 8
mov eax, 000ff00ffh
or edx, ebx
sub nDivided_Width, 1
jz short lopX_END

lopX:
and eax, dwrod ptr [ esi+000h ]
mov ecx, 000ff00ffh
add esi, 004h
and ecx, dwrod ptr [ edi+000h ]
movzx ebx, dx
shl eax, 8
movzx ebx, byte ptr [ ebp+ebx ]
shr edx, 16
or ecx, eax
movzx edx, byte ptr [ ebp+edx ]
movzx eax, ecx
shl ebx, 8
movzx eax, byte ptr [ ebp+eax ]
shr ecx, 16
shl edx, 24
movzx ecx, byte ptr [ ebp+ecx ]
or eax, edx
add edi, 004h
shl ecx, 16
mov edx, 0ff00ff00h
or eax, ebx
and edx, dwrod ptr [ edi+000h ]
mov ebx, 0ff00ff00h
or ecx, eax
and ebx, dword ptr [ esi+000h ]
shr edx, 8
mov eax, 000ff00ffh
mov dwrod ptr [ edi-004h ], ecx
or edx, ebx
sub nDivided_Width, 1
jnz short lopX
131111:2001/07/19(木) 16:27
(続き)

lopX_END:
and eax, dwrod ptr [ esi+000h ]
mov ecx, 000ff00ffh
and ecx, dwrod ptr [ edi+000h ]
movzx ebx, dx
shl eax, 8
movzx ebx, byte ptr [ ebp+ebx ]
shr edx, 16
or ecx, eax
movzx edx, byte ptr [ ebp+edx ]
movzx eax, ecx
shl ebx, 8
movzx eax, byte ptr [ ebp+eax ]
shr ecx, 16
shl edx, 24
movzx ecx, byte ptr [ ebp+ecx ]
or eax, edx
shl ecx, 16
or eax, ebx
or ecx, eax
mov dwrod ptr [ edi+000h ], ecx
132デフォルトの名無しさん:2001/07/19(木) 16:28
>>127
全角アルファベットあたりがかなり難解。
13364:2001/07/19(木) 20:33
sagaって来たね(藁
そろそろ終了か!?
134124:2001/07/19(木) 22:16
PentiumIIでは>>122より>>86が若干速いみたいに書いたけど、
コードのアライメントによって微妙に変わってくるね。当たり前だけど。
PentiumIIではほとんど同じ速度みたい。
>>130>>122>>86より速いということはなかった。
135デフォルトの名無しさん:2001/07/26(木) 16:49
JMP _NATUYASUMI;
136デフォルトの名無しさん:2001/07/26(木) 17:19
>>127
マジで言ってるのかなー?
CPUはマシン語以外理解できないと思うんだけど。
137デフォルトの名無しさん:2001/07/26(木) 21:54
hage
138デフォルトの名無しさん:2001/08/12(日) 03:29
sage
139デフォルトの名無しさん:2001/08/23(木) 16:50
もうネタないかな?
だれかアセンブラで高級言語作って!