16

組み立てについて基本的な質問があります。

レジスタがメモリでも機能するのに、なぜレジスタに対してのみ算術演算を実行する必要があるのでしょうか。

たとえば、次の両方が(本質的に)同じ値を回答として計算する原因になります。

スニペット1

.data
    var dd 00000400h

.code

    Start:
        add var,0000000Bh
        mov eax,var
        ;breakpoint: var = 00000B04
    End Start


スニペット2

.code

    Start:
        mov eax,00000400h
        add eax,0000000bh
        ;breakpoint: eax = 0000040B
    End Start



私が見ることができることから、ほとんどのテキストとチュートリアルは主にレジスターで算術演算を行います。レジスターを操作する方が速いですか?

編集:それは速かった:)

いくつかの素晴らしい答えが与えられました。最初の良い答えに基づいて最良の答えが選ばれました。

4

9 に答える 9

29

コンピュータのアーキテクチャを見ると、一連のメモリ レベルがあります。CPU に近いものは高速で (ビットあたり) 高価なため小型であり、反対側には大きくて低速で安価なメモリ デバイスがあります。現代のコンピューターでは、これらは通常次のようなものです。

 CPU registers (slightly complicated, but in the order of 1KB per a core - there
                are different types of registers. You might have 16 64 bit
                general purpose registers plus a bunch of registers for special
                purposes)
 L1 cache (64KB per core)
 L2 cache (256KB per core)
 L3 cache (8MB)
 Main memory (8GB)
 HDD (1TB)
 The internet (big)

時間が経つにつれて、キャッシュのレベルがどんどん追加されてきました。CPU にオンボード キャッシュがなかった時代を思い出すことができます。最近では、HDD にはオンボード キャッシュが付属しており、インターネットはさまざまな場所 (メモリ、HDD、キャッシュ プロキシ サーバーなど) にキャッシュされています。

CPU から離れるごとに、帯域幅が劇的に (多くの場合桁違いに) 減少し、レイテンシが増加します。たとえば、HDD は 100MB/s で 5ms のレイテンシーで読み取ることができますが (これらの数値は正確ではない可能性があります)、メイン メモリは 6.4GB/s で 9ns のレイテンシーで読み取ることができます (大きさ!)。CPU を必要以上に長く待機させたくないため、レイテンシーは非常に重要な要素です (これは、パイプラインが深いアーキテクチャの場合に特に当てはまりますが、それについてはまた別の機会に説明します)。

同じデータを何度も何度も再利用することが多いため、後続の操作のために小さな高速キャッシュにデータを配置することは理にかなっています。これは時間的局所性と呼ばれます。局所性のもう 1 つの重要な原則は、空間的局所性です。、これは、互いに近いメモリ位置がほぼ同時に読み取られる可能性が高いことを示しています。このため、RAM から読み取ると、はるかに大きな RAM ブロックが読み取られ、オン CPU キャッシュに入れられます。これらの局所性の原則がなければ、メモリ内の任意の場所が一度に読み取られる可能性が等しくなる可能性があるため、次にアクセスされるものを予測する方法がなく、すべてのレベルのキャッシュ世界では速度が向上しません。ハードドライブをそのまま使用することもできますが、ページング時にコンピューターが停止するのがどのようなものか知っていると思います (基本的に HDD を RAM の拡張として使用します)。概念的には、ハード ドライブ以外にメモリを持たないことも可能です (多くの小型デバイスには単一のメモリがあります)。

レジスター (および少数のレジスターのみ) を使用することのもう 1 つの利点は、命令を短くできることです。2 つ (またはそれ以上) の 64 ビット アドレスを含む命令がある場合、いくつかの長い命令が必要になります。

于 2010-03-02T06:15:55.557 に答える
10

レジスタははるかに高速であり、メモリ上で直接実行できる操作もはるかに制限されています。

于 2010-03-02T05:01:57.310 に答える
4

x86 は、アセンブリを学習する可能性のある他のほとんどすべての「通常の」CPU と同様に、レジスタ マシン1です。プログラムできるものを設計する方法は他にもあります (たとえば、メモリ内の論理的な「テープ」に沿って動くチューリング マシンやライフ ゲーム)。パフォーマンス。

https://www.realworldtech.com/architecture-basics/2/は、アキュムレータやスタック マシンなど、現在は廃止されている可能性のある代替手段をカバーしています。ロードストアまたはレジスタメモリのいずれかになることができるx86のようなCISCは省略されていますが。x86 命令は、実際にはreg,mem にすることができます。レグ、レグ; またはmem、reg。(または直接のソースを使用します。)

脚注 1:レジスタ マシンと呼ばれる計算の抽象モデルは、レジスタとメモリを区別しません。レジスタと呼ばれるものは、実際のコンピューターのメモリに似ています。ここで言う「レジスタ マシン」とは、 1 つのアキュムレータやスタック マシンなどではなく、複数の汎用レジスタを備えたマシンを意味します。ほとんどの x86 命令には 2 つの明示的なオペランドがあります (ただし、状況によって異なります))、そのうちの 1 つまでメモリにすることができます。6502 のような 1 つのアキュムレータ レジスタへの計算しか実際には実行できないマイクロコントローラでさえ、ほとんどの場合、他のレジスタ (ポインタやインデックスなど) を持っています。アキュムレータにさまざまなものをリロードし、直接使用できる場所に配列インデックスやループカウンターを保持することさえできません。


x86 はレジスターを使用するように設計されているため、パフォーマンスを気にしたくなくても、レジスターを完全に回避することはできません。

現在の x86 CPU は、メモリ位置よりも多くのレジスタをクロック サイクルごとに読み書きできます。

たとえば、Intel Skylake は、サイクルごとに 32KiB 8 ウェイ連想 L1D キャッシュとの間で 2 つのロードと 1 つのストアを実行できますが (最良の場合)、クロックごとに 10 個以上のレジスタを読み取り、3 または 4 個 (および EFLAGS) を書き込むことができます。

レジスタ ファイルと同じ数の読み取り/書き込みポートを備えた L1D キャッシュを構築すると、(トランジスタの数/面積と消費電力の点で) 非常にコストがかかります。x86が同じパフォーマンスでレジスタを使用する方法でメモリを使用できるものを構築することは、おそらく物理的に不可能です。

また、レジスタに書き込み、再度読み取る場合、CPU がこれを検出し、結果を 1 つの実行ユニットの出力から別の実行ユニットの入力に直接転送し、ライトバック ステージをバイパスするため、基本的にレイテンシはゼロです。( https://en.wikipedia.org/wiki/Classic_RISC_pipeline#Solution_A._Bypassingを参照)。

実行ユニット間のこれらの結果転送接続は、「バイパス ネットワーク」または「転送ネットワーク」と呼ばれます。CPU がレジスタ設計のためにこれを行う方が、すべてをメモリに入れてバックアウトする必要がある場合よりもはるかに簡単です。CPU は、32 ビットまたは 64 ビットのアドレスではなく、3 ~ 5 ビットのレジスタ番号をチェックするだけで、1 つの命令の出力が別の操作の入力としてすぐに必要な場合を検出できます。(そして、これらのレジスタ番号はマシンコードにハードコーディングされているため、すぐに利用できます。)

他の人が述べたように、レジスタのアドレス指定に 3 または 4 ビットを使用すると、すべての命令に絶対アドレスがある場合よりもマシンコード形式がはるかにコンパクトになります。


https://en.wikipedia.org/wiki/Memory_hierarchyも参照してください: レジスタは、直接絶対アドレス指定のみがサポートされているメイン メモリとは別の、小さくて高速な固定サイズのメモリ空間と考えることができます。(レジスタを「インデックス」することはできません。1 つのレジスタに整数が指定されている場合、1つの insn で th レジスタNの内容を取得することはできません。)N

レジスタは単一の CPU コアに対してもプライベートであるため、順不同で実行すると、必要に応じて何でも実行できます。メモリを使用すると、他の CPU コアから見えるようになる順序を気にする必要があります。

固定数のレジスタを持つことは、CPU が順不同で実行するためにレジスタの名前を変更できるようにするための一部です。命令がデコードされたときにレジスタ番号をすぐに利用できるようにすることで、これも簡単になります。まだ知られていないレジスタへの読み取りまたは書き込みは決してありません。

Agner の命令表とは異なり、Haswell で mulss が 3 サイクルしかかからないのはなぜですか?を参照してください。(複数のアキュムレータを使用した FP ループのアンロール)レジスタの名前変更の説明、および特定の例 (後の質問の編集/私の回答の後半の部分は、複数のアキュムレータを使用したアンロールによるスピードアップを示し、同じものを再利用しても FMA レイテンシを非表示にします)建築登録を繰り返す)。


ストア フォワーディングを使用したスト​​ア バッファは、基本的に「メモリの名前変更」を行います。メモリ ロケーションへのストア/リロードは、このコア内からそのロケーションへの以前のストアおよびロードとは無関係です。(投機的に実行された CPU ブランチに、RAM にアクセスするオペコードを含めることはできますか? )

stack-args 呼び出し規則を使用した関数呼び出しの繰り返し、および/または参照によって値を返すことは、スタック メモリの同じバイトを複数回再利用できる場合です。

最初のストアがまだ入力を待っている場合でも、2 番目のストア/リロードを実行できます。(私はこれをSkylakeでテストしましたが、結果をどこかに回答に投稿したことがある場合はIDK.)

于 2017-08-10T03:11:06.967 に答える
3

「遅い」メモリバスにアクセスする必要がないため、レジスタはRAMメモリよりもはるかに高速にアクセスされます。

于 2010-03-02T05:01:44.963 に答える
1

一般的に言えば、レジ​​スタ演算ははるかに高速で、はるかに好ましいです。ただし、直接メモリ演算が役立つ場合があります。メモリ内の数値をインクリメントするだけの場合(少なくとも数百万の命令の場合は他に何もありません)、通常、単一の直接メモリ算術命令はロード/追加/保存よりもわずかに高速です。

また、複雑な配列操作を実行している場合は、通常、現在の場所と配列の終了場所を追跡するために多くのレジスタが必要です。古いアーキテクチャでは、レジスタがすぐに不足する可能性があるため、現在のレジスタをザッピングせずに2ビットのメモリを追加するオプションは非常に便利でした。

于 2010-03-02T07:58:40.603 に答える
1

レジスターは高速であるため、レジスターを使用します。通常、それらは CPU の速度で動作します。
レジスタと CPU キャッシュは、異なるテクノロジ/ファブリックで作成されて
おり、高価です。一方、RAM は安価で、100 倍遅くなります。

于 2010-03-02T05:30:42.817 に答える
0

はい、レジスタを使用する方がはるかに高速です。プロセッサからレジスタまでの物理的な距離だけを考慮して、プロシージャからメモリまでを比較したとしても、これまで電子を送信しないことで多くの時間を節約できます。つまり、より高いクロックレートで実行できます。

于 2010-03-02T05:01:46.850 に答える
0

はい-また、通常、プロシージャの呼び出し、割り込みの処理などのためにレジスタを簡単にプッシュ/ポップできます

于 2010-03-02T05:01:56.367 に答える
-2

命令セットでは、このような複雑な操作を実行できないというだけです。

add [0x40001234],[0x40002234]

あなたはレジスターを通過しなければなりません。

于 2010-03-02T05:03:13.330 に答える