問題タブ [basm]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
delphi - 8ビットを0または1の8ブールバイトに拡張するためのIntelx86アセンブリ最適化手法
私はかなり長い間アセンブラを学んでいて、パフォーマンス上の利点(もしあれば)を見るためにいくつかの簡単なプロシージャ\関数をそれに書き直そうとしています。私の主な開発ツールはDelphi2007で、最初の例はその言語で作成されますが、他の言語にも簡単に翻訳できます。
問題は次のように述べています。
8ビットのそれぞれが画面の1行のピクセルを表す符号なしバイト値を指定しました。各単一ピクセルは、ソリッド(1)またはトランスペアレント(0)にすることができます。つまり、1バイトの値に8ピクセルがパックされています。最も若いピクセル(ビット)が配列の最も低いインデックスの下に着地するように、これらのピクセルを8バイト配列にアンパックしたいと思います。次に例を示します。
以下に、問題を解決している5つの方法を示します。次に、彼らの時間比較と、それらの時間をどのように測定したかを示します。
私の質問は2つの部分で構成されています。
1.1。
方法との詳細な回答をお願いします。なぜメソッドはよりもやや遅いのですか?DecodePixels4a
DecodePixels4b
4b
4a
たとえば、コードが正しく配置されていないために処理速度が遅い場合は、特定のメソッドのどの命令をより適切に配置できるか、およびメソッドを壊さないようにする方法を教えてください。
理論の裏にある実例を見たいと思います。私はアセンブリを学んでいることを覚えておいてください。あなたの答えから知識を得て、将来、より最適化されたコードを書くことができるようにしたいと思います。
2.2。
あなたはより速いルーチンを書くことができますDecodePixels4a
か?もしそうなら、それを提示し、あなたが取った最適化のステップを説明してください。より高速なルーチンとは、ここに示されているすべてのルーチンの中で、テスト環境で最短時間で実行されるルーチンを意味します。
すべてのインテルファミリープロセッサーが許可されており、それらと互換性があります。
以下に私が書いたルーチンがあります:
そして、これが私がそれらをテストする方法です:
これが私のマシン(Win32 XP上のIntel®Pentium®E2180)の結果です。
結果はかなり安定しています。時間は、私が行った各テスト間で数パーセントしか変化しません。そしてそれは常に真実でした:Time1 > Time3 > Time 2 > Time4b > Time4a
したがって、Time4aとTime4bの違いは、メソッド内の命令の切り替えに依存すると思いますDecodePixels4b
。4%の場合もあれば、最大10%の場合もありますが、4b
常により遅くなり4a
ます。
一度に8バイトをメモリに書き込むMMX命令を使用する別の方法を考えていましたが、64ビットレジスタにバイトをアンパックする高速な方法がわかりません。
お時間をいただきありがとうございます。
貴重なご意見ありがとうございました。残念ながら、現代のCPUと比較すると、すべての人に同時に答えることができましたが、「パイプ」は1つしかなく、一度に「応答」する命令は1つしか実行できません;-)それで、いくつかのことをまとめてみますここに、あなたの答えの下に追加のコメントを書いてください。
まず、質問を投稿する前に、Wouter van Nifterickによって提示された解決策を思いついたのですが、実際にはアセンブリコードよりもはるかに低速でした。そのため、ここではそのルーチンを投稿しないことにしましたが、ループDelphiバージョンのルーチンでも同じアプローチを採用したことがわかります。それは私に悪い結果を与えていたので、そこにコメントされています。
これは私にとって謎です。WouterとPhilSのルーチンを使用してコードをもう一度実行しました。結果は次のとおりです。
Time5の結果を見てください、かなり奇妙ですね。生成されたアセンブリコードがWouterによって提供されたものと異なるため、Delphiのバージョンが異なると思います。
2番目の主要な編集:
なぜ5
私のマシンでルーチンが遅くなったのか知っています。コンパイラオプションで「範囲チェック」と「オーバーフローチェック」をチェックしました。assembler
ルーチンにディレクティブを追加9
して、それが役立つかどうかを確認しました。このディレクティブアセンブリ手順では、Delphiインラインバリアントと同じか、それよりもわずかに優れているようです。
最終結果は次のとおりです。
3番目の主要な編集:
意見では、@ Pascal Cuoqと@j_random_hackerは、ルーチン間の実行時間の違いで4a
あり4b
、5
データの依存関係が原因です。しかし、私が行ったさらなるテストに基づいて、私はその意見に反対しなければなりません。
4c
また、に基づいて新しいルーチンを発明しました4a
。ここにあります:
私はそれがかなりデータに依存していると言うでしょう。
そして、ここにテストと結果があります。事故がないことを確認するために4つのテストを行いました。また、GJによって提案されたルーチン(Time10a、Time10b)に新しい時間を追加しました。
、、、の結果が表示される場合がありますが、これら4a
は互いに非常に近いものです。何故ですか?4aから削除したので、4b(4cにはまだありません)の2つの命令:と。コード内の他の場所ではeaxの下の値を使用しないことがわかっているので、事前に予約する必要はありません。これで、私のコードには、ルーチン5のようにプッシュ/ポップのペアが1つしかありません。ルーチン5は、最初にecxでコピーを作成するため、eaxの値を事前予約しますが、ecxを事前予約しません。4b
4c
5
push eax
pop eax
したがって、私の結論は次のとおりです。5と4aと4bの実行時間の違い(3回目の編集前)はデータの依存関係には関係しませんでしたが、プッシュ/ポップ命令の追加のペアによって引き起こされました。
私はあなたのコメントに非常に興味があります。
数日後、GJはPhiSよりもさらに高速なルーチン(Time 10d)を発明しました。いい仕事GJ!
c++ - ポインタを使用してコードをPascalのアセンブリに変換します-Delphi
以下にこのコードがあり、Delphiでも使用できるようにASMに変換したいと思います。
正常に動作しますが、アセンブリバージョンを試してみると:
C ++では次の両方の方法で機能するため、機能するはずです。
ただし、Delphiでは機能しません。
アセンブリバージョンでは、配列の各要素間のオフセットサイズであるため、配列を4に乗算します。したがって、両方のバージョンは同等です。
だから、なぜそれがDelphiで動作しないのか知りたいです。Delphiでは、配列内の整数値間のオフセットサイズはC ++とは異なりますか?
私はすでに1、2、4、6、8などの多くのオフセットを試しました。また、多くの種類の配列(ポインターの配列、ポインターのみ、整数の配列など)、および多くの呼び出し規約を試しました。非asmバージョンで機能したのはcdeclだけでしたが、ASMではすべてのテストが機能しませんでした。
ありがとう。
delphi - Delphi ラベルと asm の奇妙さ?
Delphi 7 で asm 関数を作成しましたが、コードが別のものに変換されます。
push ebx
とが生成されるのはなぜpop ebx
ですか? そして、それはなぜmov eax, ebx
ですか?
のせいで部分的なスタックフレームが生成されるようですmov eax, ebx
。
この単純なテストはmov eax, edx
、そのスタック フレームを生成しますが、生成しません。
と何か関係があるようですlabel err
。それを削除すると、その部分が得られませんmov eax, *
。
なぜこれが起こるのですか?
Quality Centralでバグ レポートを作成しました。
delphi - Delphi コンパイラがアセンブリ関数をインライン化しないのはなぜですか?
時々、次のような非常に短いアセンブリ関数を記述します
インライン化に最適な候補と思われるもの:
しかし、Delphi コンパイラはそれを許可しません。なんで?
更新しました:
ldsandon のおかげで、QC に関する 5.5 年前の公開レポートが存在します。レポートには、コンパイラの asm インライン化を簡素化するためのいくつかの提案 (asm ディレクティブの拡張など) が含まれています。プロシージャ/関数レベルで「naked」ディレクティブを導入することをお勧めします。これは、プロシージャのスタック フレームを作成する必要がなく、オプションでどのレジスタ (eax、edx、および ecx) を保持する必要があるかをコンパイラに伝えるものです。
BASM コードを使用した効率的なインライン プロシージャの一般的なタスクが難しい (そして不要な場合がある) 場合は、最も重要なケース (レジスタの使用が明示的に宣言されたネイキッド関数など) でインライン化を有効にすることをお勧めします。
string - Delphi:編集ボックスに文字列を入れるときのアクセス違反?
さて、私は Delphi でいくつかのインライン アセンブリを勉強しています。アセンブリ暗号化ルーチンは、ShortString を Textbox に解析しようとするまで、すべて順調に進んでいます。
完全なコードは次のとおりです。
「edit2.Text:= TCaption(key);」という行にブレークポイントを配置すると、ShortString の「キー」が実際に適切に暗号化されていることがわかりますが、その背後にも多くの奇妙な文字が含まれています。
最初の 16 文字が実際の暗号化です。
暗号化 http://img831.imageshack.us/img831/365/29944312.png
ありがとう!
string - 長い文字列を返すDelphiアセンブリ関数
私はDelphiでインラインアセンブリプログラミングを学ぼうとしていますが、この目的のために、この記事は非常に役に立ちました。
AnsiString
ここで、長い文字列、具体的には(簡単にするために)を返すアセンブリ関数を記述したいと思います。私は書いた
説明:
文字列を返す関数には非表示var result: AnsiString
(この場合)のパラメーターがあるため、関数の先頭でeax
、結果の文字列のアドレスを保持する必要があります。次に、とをそれぞれ3と1252に設定edx
してから、を呼び出します。事実上、私はしますecx
System._LStrSetLength
ここで、3は文字列の新しい長さ(文字数=バイト)であり、1252は標準のwindows-1252コードページです。
次に、それが文字列の最初の文字のアドレスであるeax
ことを知って、文字列を「ABC」に設定するだけです。しかし、それは機能しません-それは私にナンセンスなデータまたはEAccessViolationを与えます。何が問題ですか?
アップデート
これで、2つの一見機能している実装がありますmyfunc
。1つはを採用しNewAnsiString
、もう1つはを採用してLStrSetLength
います。Delphiの文字列の内部処理(参照カウント、自動解放など)を台無しにしないという意味で、両方が正しいかどうか疑問に思わざるを得ません。
delphi - Delphiのasmプロシージャの最後に復元されるCPUレジスタ
Delphiプロシージャまたは関数をアセンブリコードで記述する場合、プロシージャの最後にどのレジスタを保存して元の値に復元する必要がありますか?
(インライン)アセンブリコードから別のDelphiプロシージャまたは関数を呼び出す場合、他の関数がレジスタを処理することを期待できますか?どのレジスタが元の値に復元され、どのレジスタが復元されない可能性がありますか?
(明らかに、同じ答えが両方の質問に当てはまります)
Delphiのデフォルトの呼び出し規約を想定しています。私はそれEAX
が32ビットの戻り値に使用されていることを知っています。また、SysUtils.pasのasmコードを見ると、、がプッシュおよび復元されているように見えますEBX
がESI
、EDI
他のコードはそうではありません。ただし、これに関するドキュメントは見つかりません。
delphi - Delphi アセンブリ ブロックでの異常な動作
この非常に短くて単純なプログラムで示されているように、Delphi のインライン アセンブリで奇妙な動作が発生しています。
これは単なる例です ( mov
ing [asdf]
intoeax
はあまり機能しませんが、この例では機能します)。このプログラムのアセンブリを見ると、
に変わりました
(OllyDbg で表される) これは明らかにクラッシュします。ただし、これを行う場合:
動作するmov eax、[ebp-4]に変わります。どうしてこれなの?私は通常C++で作業しており、そのようなインスタンス変数を使用することに慣れています。インスタンス変数を間違って使用している可能性があります。
編集:はい、それでした。に変更mov eax, [asdf]
するmov eax, [Self.asdf]
と問題が解決します。申し訳ありません。
delphi - Word変数のバイト(低/高)を交換するプロシージャ
Word変数のバイト(低/高)を交換するこの手順があります(これはSystem.Swap関数と同じことを行います)。この手順は、コンパイラの最適化がオフの場合は機能しますが、オンの場合は機能しません。誰かがこれを手伝ってくれますか?
delphi - 純粋なアセンブリで記述された関数のプロローグを削除する
Delphi 2010 を使用しています。関数のプロローグを生成しないように Delphi に指示することはできますか? 次のような純粋なアセンブリ関数をいくつか書いています。
C++ の機能のように、この関数のプロローグとエピローグを生成しないように Delphi に指示したいと思い__declspec(naked)
ます。
したがって、誰も時間を無駄にすることはありません。プロローグでこれらの関数を動作させるのに助けは必要ありません。私はすでにそれを行うことができます。それは単に大きな不便であり、メンテナンスが非常に面倒になります。コンパイラによって生成されたプロローグを手動で調べて、その長さを確認する必要があります。それが変更されると、プログラムがクラッシュします。
また、関数を一連のバイトとしてバイト配列に記述できることもわかっていますが、Delphi のプロローグの長さを調べなければならないよりもさらに悪いことです。