コンピュータアーキテクチャにおいて、ワードアドレッシングとは、コンピュータ上のメモリのアドレスがメモリのワードを一意に識別することを意味します。これは通常、バイトアドレッシング(アドレスがバイトを一意に識別する方式)と対比して用いられます。現代のコンピュータアーキテクチャのほぼすべてがバイトアドレッシングを採用しており、ワードアドレッシングは歴史的な意義しか持ちません。ワードアドレッシングを使用するコンピュータは、ワードマシンと呼ばれることもあります。

524,288 (2 19 ) ビットのメモリを提供するコンピュータを考えてみましょう。そのメモリが8 ビットのバイトを使用してバイトアドレス指定可能なフラットアドレス空間に配置されている場合、0 から 65,535 までの 65,536 (2 16 ) 個の有効なアドレスがあり、それぞれが独立した 8 ビットのメモリを表します。一方、32 ビットのワードを使用してワードアドレス指定可能なフラット アドレス空間に配置されている場合、0 から 16,383 までの 16,384 (2 14 ) 個の有効なアドレスがあり、それぞれが独立した 32 ビットを表します。
より一般的に言えば、最小アドレス指定可能単位(MAU)は、特定のメモリ抽象化の特性です。コンピュータ内の異なる抽象化は、同じ基盤となるメモリを表している場合でも、異なるMAUを使用する可能性があります。たとえば、コンピュータは命令セットでバイトアドレッシングによる32ビットアドレスを使用するかもしれませんが、CPUのキャッシュコヒーレンスシステムは64バイトのキャッシュラインの粒度でのみメモリを扱う場合があり、これにより特定のキャッシュラインを26ビットアドレスだけで識別できるため、キャッシュのオーバーヘッドが削減されます。
仮想メモリによって行われるアドレス変換は、アドレス空間の構造と幅に影響を与えることが多いが、MAU(最大アクセス単位)は変更しない。
メモリの最小アドレス指定単位(MAU)のサイズには、複雑なトレードオフが存在します。MAUを大きくすると、同じ量のメモリをより小さなアドレスでカバーできるため、プログラムのメモリ要件を大幅に削減できます。しかし、MAUを小さくすると、小さなデータ項目を効率的に処理しやすくなります。
あるプログラムが西洋占星術の12の伝統的な星座のうちの1つを格納したいとします。1つの星座は4ビットで格納できます。星座を独自のMAUに格納する場合、バイトアドレス指定では4ビットが無駄になります(効率50%)。一方、32ビットワードアドレス指定では28ビットが無駄になります(効率12.5%)。星座が他のデータと一緒にMAUに「パック」されている場合、読み書きのコストが相対的に高くなる可能性があります。たとえば、他のデータがパックされているMAUに新しい星座を書き込むには、コンピュータはMAUの現在の値を読み取り、適切なビットだけを上書きし、新しい値を再度格納する必要があります。プログラムが他のスレッドにMAU内の他のデータを同時に変更させる必要がある場合は、このコストが特に高くなります。
より一般的な例としては、テキスト文字列が挙げられます。UTF -8やASCIIなどの一般的な文字列フォーマットでは、文字列は8ビットのコードポイントのシーケンスとして格納されます。バイトアドレッシングでは、各コードポイントをオーバーヘッドなしで個別にアドレス指定可能なMAUに配置できます。32ビットワードアドレッシングでは、各コードポイントを個別のMAUに配置するとメモリ使用量が300%増加するため、大量のテキストを扱うプログラムには適していません。隣接するコードポイントを1つのワードにパックすることで、このコストを回避できます。ただし、テキストを扱う多くのアルゴリズムでは、コードポイントを個別にアドレス指定できることが望まれます。パックされたコードポイントでこれを行うには、アルゴリズムはワード内の文字のオフセットも格納する「ワイド」アドレスを使用する必要があります。このワイドアドレスをプログラムのメモリ内の別の場所に格納する必要がある場合、通常のアドレスよりも多くのメモリが必要になる可能性があります。
プログラム全体に対するこれらの影響を評価するために、大きくて複雑なページを表示するウェブブラウザを考えてみましょう。ブラウザのメモリの一部は、画像やテキストなどの単純なデータを格納するために使用されます。ブラウザは、このデータをできるだけ効率的に格納することを選択する可能性が高く、MAUのサイズに関係なく、ほぼ同じ量のメモリを占有します。他のメモリは、ページ上のさまざまなオブジェクトのブラウザモデルを表し、これらのオブジェクトには、オブジェクト同士、画像やテキストデータなどへの多くの参照が含まれます。これらのオブジェクトを格納するために必要なメモリ量は、コンピュータのアドレス幅に大きく依存します。
プログラム内のすべてのアドレスが32ビットだと仮定すると、このウェブページは約10ギガバイトのメモリを占有することになる。
このように、ワードアドレッシングを用いることで、コンピュータはアドレス幅を増やすことなく、またそれに伴うメモリ使用量の大幅な増加を招くことなく、より多くのメモリをアドレス指定できるようになります。ただし、これはワーキングセットのサイズが比較的狭い範囲に限られ、アプリケーションによっては実行時のオーバーヘッドが大きくなる可能性があります。画像、テキスト、ファイル、ネットワークトラフィックなど、バイト指向のデータを扱う処理が比較的少ないプログラムは、この恩恵を最も受けやすいでしょう。
ワードアドレッシングを使用するコンピュータ上で動作するプログラムは、より小さなメモリ単位へのアクセスをエミュレートすることで、その小さなメモリ単位でも動作させることができます。ロードの場合、まず囲んでいるワードをロードし、次に必要なビットを抽出します。ストアの場合、まず囲んでいるワードをロードし、新しい値を所定の位置にシフトし、必要なビットを上書きしてから、囲んでいるワードを保存します。
UTF-8文字列から連続する4つのコードポイントを32ビットワードにパックする必要があるとします。最初のコードポイントはビット0~7、2番目は8~15、3番目は16~23、4番目は24~31を占めるかもしれません。(メモリがバイト単位でアドレス指定可能であれば、これはリトルエンディアンのバイト順になります。)
サブワードアクセスに必要なコードを明確に説明しつつ、例を特定のワードアドレス指定アーキテクチャに過度に依存させないようにするため、以下の例ではMIPSアセンブリ言語を使用します。実際には、MIPSは8ビットおよび16ビット値のロードとストアを直接サポートするバイトアドレス指定アーキテクチャですが、この例では32ビットのロードとストアのみを提供し、32ビットワード内のオフセットはアドレスとは別に格納する必要があると仮定します。MIPSが選ばれた理由は、これらの操作をより便利にする特別な機能を持たないシンプルなアセンブリ言語であるためです。
プログラムがr1レジスタ内のアドレスにあるワードから3番目のコードポイントをレジスタに読み込みたいとしますr2。命令セットに他のサポートがない場合、プログラムはワード全体をロードし、16だけ右シフトして最初の2つのコードポイントを削除し、4番目のコードポイントをマスクする必要があります。
ldw $r1, 0($r2) # 完全なワードをロードする srl $r1, $r1, 16 # 16だけ右にシフト andi $r1, $r1, 0xFF # 他のコードポイントをマスクする
オフセットが静的に既知ではなく、代わりにビットオフセットがレジスタに格納されている場合はr3、もう少し複雑なアプローチが必要になります。
ldw $r1, 0($r2) # 完全なワードをロードする srlv $r1, $r1, $r3 # ビットオフセット分だけ右シフトする andi $r1, $r1, 0xFF # 他のコードポイントをマスクする
代わりに、プログラムがレジスタ内のコードポイントを、r1アドレス内のワードの3番目のコードポイントに割り当てたいとしますr2。命令セットからのその他のサポートがない場合、プログラムはワード全体をロードし、そのコードポイントの古い値をマスクし、新しい値を所定の位置にシフトし、値をマージし、ワード全体を再度格納する必要があります。
sll $r1, $r1, 16 # 新しい値を左に16シフトする lhi $r5, 0x00FF # 3バイト目を選択するための定数マスクを構築します nor $r5, $r5, $zero # マスクを反転して3バイト目をクリアします ldw $r4, 0($r2) # 完全なワードをロードする および $r4、$r5、$r4 # ワードから3バイト目をクリアします または $r4、$r4、$r1 # 新しい値を単語にマージします stw $r4, 0($r2) # 結果を完全なワードとして保存する
繰り返しますが、オフセットが代わりにに格納されている場合はr3、より複雑なアプローチが必要になります。
sllv $r1, $r1, $r3 # 新しい値をビットオフセット分左にシフトします llo $r5, 0x00FF # バイトを選択するための定数マスクを構築します sllv $r5, $r5, $r3 # マスクをビットオフセット分左にシフトする nor $r5, $r5, $zero # マスクを反転して、選択したバイトをクリアします ldw $r4, 0($r2) # 完全なワードをロードする および $r4、$r5、$r4 # ワードから選択したバイトをクリアします または $r4、$r4、$r1 # 新しい値を単語にマージします stw $r4, 0($r2) # 結果を完全なワードとして保存する
このコードシーケンスは、別のスレッドがワード内の他のバイトを同時に変更できないことを前提としています。同時変更が可能な場合、変更内容の一部が失われる可能性があります。この問題を解決するには、最後の数個の命令をアトミックな比較交換ループに変換する必要があります。これにより、同時変更が発生した場合でも、新しい値で操作が繰り返されるだけです。この場合、メモリバリアは不要です。
ワードアドレスとワード内のオフセットのペアをワイドアドレス(ファットアドレスまたはファットポインタとも呼ばれる)と呼びます。(これは、配列の境界など、他の種類の補助データを格納するためのワイドアドレスの他の用途と混同しないでください。)格納されるオフセットは、ビットオフセットまたはバイトオフセットのいずれかです。上記のコードシーケンスでは、オフセットをシフトカウントとして使用するため、オフセットがビット単位で指定されていることが有利です。バイト選択を直接サポートするアーキテクチャでは、バイトオフセットを格納する方が望ましい場合があります。
これらのコードシーケンスでは、追加のオフセットをベースアドレスと一緒に格納する必要があり、実質的にアドレス全体のストレージ要件が2倍になります。ワードマシンでは、アドレス自体がアクセス効率を高めるために他のデータとパックされていないことが多いため、これは必ずしも当てはまりません。たとえば、Cray X1は64ビットワードを使用しますが、アドレスは32ビットのみです。アドレスがメモリに格納されるときは、独自のワードに格納されるため、バイトオフセットをワードの上位32ビットに配置できます。このシステムでワイドアドレスを使用することの非効率性は、このオフセットを操作し、ワード内でバイトを抽出および挿入するための余分なロジックだけであり、メモリ使用量には影響しません。
コンピュータの最小アドレス指定単位は、必ずしもコンピュータの命令セットの最小メモリアクセスサイズと同じではありません。たとえば、コンピュータはバイトアドレッシングを使用するものの、1バイトを直接読み書きする命令を提供しない場合があります。プログラムは、上記のコード例のように、ビット操作を用いてソフトウェアでこれらの操作をエミュレートすることが求められます。これは、DEC AlphaやCray X1など、32ビットスーパーコンピュータやミニコンピュータの後継として設計された64ビットコンピュータアーキテクチャでは比較的よく見られる特徴です。
C規格では、ポインタは通常のアドレス表現を持つことが期待されています。C では、ビットフィールドを除くあらゆるオブジェクトへのポインタを作成できます。これには、バイト配列の各要素も含まれます。ワードアドレッシングを使用するコンピュータ向けの C コンパイラは、ポインタのサイズに応じて、異なる型のポインタに対して異なる表現を使用することがよくあります。ワードを埋めるのに十分な大きさの型へのポインタは単純なアドレスになりますが、char*やのようなポインタvoid*はワイドポインタになります。ワイドポインタとは、ワードのアドレスと、そのワード内のバイトのオフセットのペアです。したがって、ポインタの型間の変換は必ずしも簡単な操作ではなく、誤って行うと情報が失われる可能性があります。
C のサイズは、structその C へのポインタの表現を決定する際に常に既知であるとは限らないため、上記の規則を確実に適用することはできません。コンパイラは、より効率的なポインタ表現を使用できるように、structC の開始位置を調整する必要がある場合があります。struct
ldq_uおよび) を便利に提供します。 [ 2 ] アーキテクチャの後のバイト ワード拡張 (BWX) では、Alpha 21164a から 8 ビットおよび 16 ビットのロードおよびストアが追加されました。[ 3 ] この拡張も、Alpha が常にバイト アドレス指定を使用していたため、深刻なソフトウェアの非互換性なしに可能でした。stq_u