言語はCPU設計にどのように影響しましたか?[閉まっている]


44

私たちはされていることが多い語ったが、これは真実ではない、ハードウェアは、プログラムがそれだけでコンパイルされたバイナリコードを見ているように書かれている言語を気にしないこと。たとえば、謙虚なZ80を考えてみましょう。8080命令セットへのその拡張には、C-スタイル(NULLで終了する)文字列をスキャンするのに役立つCPIRなどの命令が含まれますstrlen()。設計者は、Cプログラムの実行(文字列の長さがヘッダーにあるPascalとは対照的に)が、設計で使用される可能性が高いことを特定している必要があります。別の古典的な例は、Lisp Machineです。

他にどんな例がありますか?たとえば、特定のプロセッサが特定の言語の規則を好むようにする命令、レジスタの数とタイプ、アドレス指定モードはありますか?私は特に同じ家族の改訂に興味があります。


3
Z-80にはLDIR命令も含まれていたことを忘れないでください。長さがわかっているときに文字列をコピーするときに非常に便利です(長さがヘッダーに格納されているPascalなど)。
TMN

27
1. Z-80は、K&Rの初版の3年前の1975年に、UnixとCがいくつかのコンピューターであいまいなオペレーティングシステムと言語であったときに設計されました。2.文字列の長さを「ヘッダー内」にすることを義務付けるPascalについては何もありません。3.当時の主要なマイコンOSであったCP / Mの文字列は、「\ 0」ではなく「$」文字で終了していました。CPIRは任意の文字を検索できます。4. CPIRは、他の-IRおよび-DR命令と同様に、CPDR(後方検索)と一致します。結論:CPIRはCプログラミング言語とは関係ありません。これは単なるバイト検索命令です。
librik

4
Cによって強制されるものの最大(そしてハードウェア設計者にとって最も厄介なものの1つ)は、バイトアドレッシングです。この忌み嫌いがなければ、CPUはよりシンプルで高速でした。
SKロジック

1
@ SK-logic:POSIX標準ではバイトアドレッシングが必要ですが、C標準では必要ありません。sizeof(int)1 に等しい実装では、型charに署名するint必要があります(型のすべての値を保持できる必要があるためchar)。私はどこのマシンのコードを書いたcharintの両方の16ビット符号付き整数です。最大の困難は、型変換に共用体を使用できないことであり、大量のバイトを効率的に保存するには、手動でのパックとアンパックが必要です。これらの問題は、Cでsizeof(int)== sizeof(long)である可能性と比較して、マイナーです。なぜなら...
supercat

2
...これは、2つのunsigned int値の差を保持することが保証されている標準タイプがないことを意味します。C99はその状況を改善しましたが、C99以前は、潜在的に負の値を型の値と比較する安全なシングルステップの方法はありませんでしたunsigned int(比較を行う前に数値が負かどうかをテストする必要があります)。
-supercat

回答:


20

既存の回答は、ISAの変更に焦点を当てています。他のハードウェアの変更もあります。たとえば、C ++は一般的に仮想呼び出しにvtableを使用します。Pentium M以降、Intelには仮想関数呼び出しを高速化する「間接分岐予測」コンポーネントがあります。


6
また、Berkeley RISCアーキテクチャには「レジスタファイル」の概念が含まれていたため、関数をレジスタに「スピル」させる代わりに、8つのレジスタのブロックが各関数に与えられました。これは、短いメソッドへの多くのメソッド呼び出しで構成される傾向があるため、オブジェクト指向コードをかなり高速化しました。
TMN

1
これは有効な例ではありません。「表関数ポインタの」設計がされて、多くの動的リンクのシナリオでは、例えば、Windows上のDLLのインポートとエクスポートを介して使用し、また、Cプログラムで使用します。プロセッサが特定の用途に最適化されていることを示すと主張できるかもしれませんが、言語固有ではありません。
-DeadMG

@DeadMG:他のケースが恩恵を受けました、それは本当です。しかし、C ++が普及するまで、CPUの設計は影響を受けませんでした。そしてそれが提起された問題でした。同様に、TMNにはレジスタファイルに関するポイントがあります。アセンブリには、そのような明確な機能の概念がありませんでした。機能は、今日一般的に理解されているように、Algol 60にまでさかのぼるため、Algol 60はCPUレジスタファイルの設計に影響を与えたと言えます。
–MSalters

14

Intel 8086命令セットには、戻りアドレスをポップした後にスタックポインター値を追加する「ret」のバリエーションが含まれています。これは、関数の呼び出し元が関数呼び出しを行う前に引数をスタックにプッシュし、後でそれらをポップオフする多くのPascal実装に役立ちます。ルーチンが4バイト分のパラメーターを受け入れる場合、「RET 0004」で終了してスタックをクリーンアップできます。そのような命令がなければ、そのような呼び出し規約では、コードが戻りアドレスをレジスタにポップし、スタックポインタを更新してから、そのレジスタにジャンプする必要があります。

興味深いことに、元のMacintoshのほとんどのコード(OSルーチンを含む)は、68000に簡単な命令がないにもかかわらず、Pascal呼び出し規則を使用していました。この呼び出し規則を使用すると、パラメータを取るすべての関数のリターンサイトでの4〜6バイトのコード。


これにENTER対応するものもありRET nます
...-herby

1
@herby:ENTERオリジナルの8086には存在しないと思います。それ以降のプロセッサが付属しています。ただし、興味深い点があります:BPベースのアドレス指定モードは、スタックパラメーターとフレームポインターを介してアクセスされるローカルの使用を中心に明確に設計されています。特に(1)純粋なアセンブリ言語コードはスタックよりもレジスタの値を使用する傾向が高いこと、(2)[SP + nn]アドレス指定は、スタック上のものにアクセスするアセンブリ言語プログラムの場合よりも重要です
...-supercat

...手書きのアセンブリコード用。コンパイラは一般に、生成されたすべての命令について、SPとBPの比較方法を知っています。たとえば、SPがBP-8の場合、コンパイラが[SP + 20]よりも[BP + 12]に対処するのは実際には簡単ではありません。再コンパイル時に、コンパイラがコードブロックの周囲に別のPUSH / POPを追加する必要がある場合、SPベースのオフセットを適切に調整できます。一方、手書きアセンブリでは、PUSH / POPを追加するには、それらの間でコードを微調整する必要があります。したがって、フレームポインターは主に、高レベル/ asmコードを組み合わせた場合の利点です。
supercat

再コンパイルせずにコードを再利用する可能性も、BPアドレッシングの限界的なユーザビリティポイントになります。そして、BPアドレス指定は一種の標準であるため、神はBPアドレス指定命令がSPアドレス指定よりも回路内で高速でないかどうかを知っています
...-herby

3
@herby:実際、コンパイラーが一般的にフレームポインターを使用している理由の大部分は、デバッグに関係していると思われます。このような規則を使用していないプログラムをデバッグするには、コンパイラーがすべての命令のSP-BPオフセットをリストしたファイルを生成し、デバッガーが使用する必要があります。このような詳細なメタデータは今日一般的です(ガベージコレクション言語を実用的にするための重要な部分です)が、必要なRAMの量は30年前には受け入れられなかったでしょう。
-supercat

10

1つの例はMIPSです。これには、オーバーフローをトラップおよび無視するための両方がaddありadduます。(またsubsubu。)明示的にオーバーフローを処理するAda(私は思う-実際にはAdaを使用したことはない)のような言語には最初のタイプの命令が必要で、Cのようなオーバーフローを無視する言語には2番目のタイプの命令が必要でした

記憶が正しければ、実際のCPUのALUには、オーバーフローを追跡するための追加の回路がいくつかあります。人々が気にかけている言語がCだけだったら、これは必要ないでしょう。


関連するかどうかはわかりませんが、これらの命令はおそらく、安全なメモリ割り当てなど、nmemb*size+offsetバイトを割り当てているときにオーバーフローが発生しないことを確認する必要がある場合など、他の状況でも役立ちます。
NikiC

@NikC:adduとのsubu命令(オーバーフローをチェックしない命令)は、Cを幸せにするために追加された命令だと思っていました。もちろん、私は本当に知りません-私たちは講義で漠然とそれをカバーしただけで、私は確かに建築の専門家ではありません:P。
ティコンジャービス

そうそう、私は逆のことを考えていた、ごめんなさい:/
NikiC

8

バロウズ5000シリーズはALGOLを効率的にサポートするように設計されており、IntelのiAPX-432はAdaを効率的に実行するように設計されています。Inmos Transputerには独自の言語であるOccamがありました。Parallax "Propeller"プロセッサは、独自のBASICバリアントを使用してプログラムされるように設計されたと思います。

言語ではありませんが、VAX-11命令セットにはプロセスコンテキストを読み込むための単一の命令があり、これはVMS設計チームからの要求の後に設計されました。詳細は覚えていませんが、ISTRの実装には非常に多くの命令が必要だったため、スケジュールできるプロセスの数に重大な上限がありました。


これらのデザインが特に適している理由は何ですか?たとえば、AdaはiAPXのどの機能から特に恩恵を受けますか?
ガイウス

iAPX-432のAdaターゲットは、失敗したデザインを他のものよりも大きな期待を持って何かに添付することで保存しようとしていることを示すISTR。
AProgrammer

@AProgrammer:iAPX-432は最初からAdaを使用するように設計されていると確信しています。アセンブリ言語プログラミングを思いとどまらせ、すべてにAdaを使用することを人々に強制するために、Intelは命令セットを公開しなかったという噂さえ覚えています。
TMN

1
@ TMN、Intelの432プロジェクトは1975年に開始され、1981年に導入されました(Wikipedia)。アイアンマン(Adaの最終要件)は1977年1月に発行され、グリーンは1979年5月に選択され、修正され、最終結果は1980年7月に軍事規格として公開されました。iAPX-432はAdaの使用開始。(これは後の典型的な「セマンティックギャップを埋める」プロセッサであり、代替の検索が開始された時点では通常の欠点があります。Adaプロセッサとして販売することは、失敗した設計を保存するための暫定的なものでした-Intel以外の誰も使用しなかったISTR )
AProgrammer

1
@AProgrammer:うーん、あなたは正しいようです。私は432のリードアーキテクトからこの論文を見つけました。要約では、彼は「432はAdaを実行するように設計されたため、アーキテクチャと言語のこの密接な一致は発生しませんでした」と述べました。私は私の古い432本を掘り下げて、それが何を言っているのかを見なければなりません。
TMN

8

これまで誰も言及していないように思われることの1つは、コンパイラの最適化の進歩(基本言語はほとんど無関係)が、CISC命令セット(ほとんどが人間によってコーディングされるように設計された)からRISC命令セット(ほとんどがコンパイラーによってコーディングされるように設計されています。)


5

Motorola 68000ファミリは、CPUを介したデータのコピーを非常に効率的かつコンパクトにする自動インクリメントアドレスモードを導入しました。

[更新された例]

これは68000アセンブラーに影響を与えるC ++コードでした

while(someCondition)
    destination[destinationOffset++] = source[sourceOffset++]

従来のアセンブラーで実装されています(擬似コード、68000アセンブラーコマンドを忘れていました)

adressRegister1 = source
adressRegister2 = destination
while(someCondition) {
    move akku,(adressRegister1)
    move (adressRegister2), akku
    increment(adressRegister1, 1)
    increment(adressRegister2, 1)
}

新しいadressmodeでは、それは似たようなものになりました

adressRegister1 = source
adressRegister2 = destination
while(someCondition) {
    move akku,(adressRegister1++)
    move (adressRegister2++), akku
}

4ではなく、ループごとに2つの命令のみ。


1
これは、特定の言語の規則によってどのような影響を受けましたか?
ガイウス

更新された例を参照
k3b

ああ、68010でのDBxxループの最適化を思い出させます。-
ガイウス

7
実際、あなたはこれを後方に持っていると思います。Auto [in | de] crementアドレッシングはPDP-11命令セットの一部であり、Cの設計に影響を与えた可能性があります。
TMN12年

5

IBMのZシリーズメインフレームは、1960年代からのIBM 360の子孫です。

特にCOBOLおよびFortranプログラムを高速化するためにいくつかの命令がありました。典型的な例は、BXLE「インデックスが低いか等しい場合の分岐」です。これは、ほとんどのFortran forループまたはPERFORM VARYING x from 1 by 1 until x > n単一の命令にカプセル化されたCOBOL です。

COBOLプログラムで一般的な固定小数点10進数演算をサポートするパック10進数命令のファミリもあります。


子孫を意味すると思います。
時計仕掛けミューズ

@ X-Zero-おっと!早朝、いないなどのシステムに十分なcaffiene .......
ジェームズ・アンダーソン

1
さらに興味深いのは、TI 32050 DSPのブロック繰り返し命令です。そのオペランドは、ループの最後の命令に続く命令のアドレスです。ループカウントレジスタをロードしてからブロックリピート命令を実行すると、ターゲットまでの(ただし、ターゲットを含まない)命令が指定された回数だけ繰り返されます。FORTRAN DOループを非常に強く連想させます。
supercat

@supercat名前に値するすべてのDSPには、ゼロオーバーヘッドループ、単一命令の積和演算、およびビット反転アドレス指定モードの3つの機能が含まれています。Manが知っているほぼすべてのDSPアルゴリズムはループを使用します。最も一般的な2つのアルゴリズムは、積和演算のループであるFIRフィルターと、ビット反転アドレッシングが重要なFFTです。多くのDSPには、1命令の基数2 FFTバタフライ演算、または1命令のバタフライを作成するために使用できるデュアル乗算/加算が含まれています。
ジョンR.ストローム

@ JohnR.Strohm:私が見たすべてのDSPにはrepeat-multiply-accumulateが含まれていますが、それらのすべてに、より一般化されたゼロオーバーヘッドループが含まれているわけではありません。実際、多くの「従来のプロセッサ」コードでも役立つので、なぜそのようなループが「DSP」機能だけと見なされるべきかはよくわかりません。
-supercat

3

初期のIntel CPUには次の機能があり、それらの多くは64ビットモードで廃止されました。

  • ENTER、LEAVE、およびRET nn命令[初期のマニュアルでは、ネストされたプロシージャをサポートするPascalなどのブロック構造化言語用に導入されたことが明示されています]
  • BCD演算を高速化するための指示(AAA、AAMなど)。x87のBCDサポートも
  • カウントループを実装するためのJCXZおよびLOOP命令
  • INTO、算術オーバーフローでトラップを生成するため(例:Ada)
  • テーブルルックアップ用のXLAT
  • 配列の境界を確認するための境界

多くのCPUのステータスレジスタにある符号フラグは、符号付きおよび符号なしの演算を簡単に実行するために存在します。

SSE 4.1命令セットは、カウントおよびゼロ終了(PCMPESTRなど)の両方のストリング処理用の命令を導入します

また、多くのシステムレベルの機能が、コンパイルされたコードの安全性をサポートするように設計されていることを想像できました(セグメント制限チェック、パラメーターコピーを使用したコールゲートなど)。


3

主にモバイルデバイスに搭載されている一部のARMプロセッサには、ハードウェアJVMインタープリターであるJazelle拡張機能が含まれます。Javaバイトコードを直接解釈します。Jazelle対応JVMは、ハードウェアを使用して実行を高速化し、JITの多くを排除できますが、バイトコードをチップで解釈できない場合でも、ソフトウェアVMへのフォールバックは保証されます。

このようなユニットを備えたプロセッサには、プロセッサを特別な「Jazelleモード」にするBXJ命令が含まれています。または、ユニットのアクティブ化が失敗した場合、通常の分岐命令として解釈されます。ユニットは、ARMレジスタを再利用してJVM状態を保持します。

Jazelleテクノロジーの後継はThumbEEです


2

私が知る限り、これは過去により一般的でした。

ジェームズゴスリングが、JVMバイトコードをより良く処理できるハードウェアを作ろうとしている人がいると言った質問のセッションがありますがこれらの人々は、一般的な「汎用」Intel x86(おそらく巧妙な方法でバイトコード)。

彼は、大企業が製品に巨額の資金を投じているため、一般的な一般的なチップ(Intelなど)を使用する利点があると述べました。

ビデオはチェックアウトする価値があります。彼はこれについて19分または20分で話します。


2

私は簡単なページ検索を行いましたが、Forthを実行するために特別に開発されたCPUについて誰も言及していないようです。Forthのプログラミング言語はスタックコンパクト、ベース、及び制御システムに使用されます。


2

インテルiAPX CPUは、特にオブジェクト指向言語のために設計されました。ただし、うまくいきませんでした。

iAPX 432インテルアドバンスド・プロセッサ・アーキテクチャは)3つの集積回路のセットとして1981年に導入されたインテル初の32ビットマイクロプロセッサの設計でした。1980年代のIntelの主要な設計を目的としており、多くの高度なマルチタスクおよびメモリ管理機能を実装していました。そのため、この設計はマイクロメインフレームと呼ばれていました...

iAPX 432は「完全に高級言語でプログラムされるように設計され」Adaが主要であり、ハードウェアとマイクロコードオブジェクト指向プログラミングガベージコレクションを直接サポートしていました。さまざまなデータ構造の直接サポートは、iAPX 432の最新のオペレーティングシステムを通常のプロセッサよりもはるかに少ないプログラムコードで実装できるようにすることも目的としていました。これらのプロパティと機能により、当時のほとんどのプロセッサ、特にマイクロプロセッサよりもはるかに複雑なハードウェアとマイクロコードの設計が行われました。

当時の半導体技術を使用していたインテルのエンジニアは、設計を非常に効率的な最初の実装に変換することができませんでした。時期尚早のAdaコンパイラの最適化の欠如に加えて、これはかなり遅いが高価なコンピューターシステムに寄与し、同じクロック周波数(1982年初期)で新しい80286チップの約1/4の速度で典型的なベンチマークを実行しました。

かなり低プロファイルで低価格の8086ラインとの最初のパフォーマンスギャップが、おそらく後者(x86として知られる)をiAPX 432に置き換えるインテルの計画が失敗した主な理由です。エンジニアは次世代の設計を改善する方法を見つけましたが、iAPX 432 機能アーキテクチャは、単純化されたサポートではなく、実装のオーバーヘッドと見なされるようになりました。

iAPX 432プロジェクトは、Intelにとって商業的な失敗でした...


論文を読んで、デザインの多くの側面が、今日人気のあるオブジェクト指向フレームワークで役立つ可能性があるようです。32ビットのオブジェクトIDと32ビットのオフセットを組み合わせて使用​​するアーキテクチャは、多くの場合、オブジェクトIDがすべて64ビットであるものよりも優れたキャッシュパフォーマンスを提供できます(ほとんどの場合、数十億のオブジェクトを使用するアプリケーションは、良好代わりに、より大きいものを有することによって提供することが、一つのオブジェクトのバイト数十億を格納することになる一方がより良い小さなオブジェクトにそれを細分配信されるであろう。
supercat

1

68000にはMOVEMがあり、これは複数のレジスタを1つの命令でスタックにプッシュするのに最も適していました。

コード全体でJSR(Jump SubRoutine)の前にMOVEM(MOVE Multiple)が表示されている場合、Cに準拠したコードを扱っていることを一般的に知っています。

MOVEMでは、デスティネーションレジスタの自動インクリメントが許可されており、各ユーザーはデスティネーションでのスタックを続行でき、自動デクリメントの場合はスタックから削除できます。

http://68k.hax.com/MOVEM


1

AtmelのAVRアーキテクチャは、完全にCでのプログラミングに適した設計になっています。たとえば、このアプリケーションノートはさらに詳しく説明します。

IMOこれはrockets4kidsの優れた回答と密接に関連しており、初期のPIC16-sは直接アセンブラープログラミング用に開発され(合計40命令)、後のファミリーはCをターゲットにしています。


1

8087数値コプロセッサーが設計されたとき、言語ではすべての浮動小数点演算を最高精度の型を使用して実行し、結果を低精度の変数に割り当てるときに結果を低精度にのみ丸めることがかなり一般的でした。たとえば、元のC標準では、シーケンスは次のとおりです。

float a = 16777216, b = 0.125, c = -16777216;
float d = a+b+c;

昇格abdouble追加し、追加し、昇格cdouble、追加し、結果をに丸めて保存しfloatます。多くの場合、コンパイラがtype floatで直接操作を実行するコードを生成する方が高速でしたが、type doubleでのみ動作する一連の浮動小数点ルーチンと、に変換するルーチンを持っている方が簡単でした以下からfloatの操作を処理するためのルーチンの別のセットを持っているよりも、floatdouble。8087は算術へのアプローチを中心に設計されており、80ビット浮動小数点型を使用してすべての算術演算を実行します[80ビットが選択された理由は次のとおりです。

  1. 多くの16ビットおよび32ビットプロセッサでは、仮数と指数の間でバイトを分割する値を処理するよりも、64ビットの仮数と指数を処理する方が高速です。

  2. 使用している数値型の完全な精度まで正確な計算を実行することは非常に困難です。たとえばlog10(x)のようなものを計算しようとする場合、64ビットの1ulp以内の正確な結果を計算するよりも、80ビット型の100ulp以内の正確な結果を計算する方が簡単かつ高速です。タイプし、前者の結果を64ビット精度に丸めると、後者よりも正確な64ビット値が生成されます。

残念ながら、この言語の将来のバージョンでは、浮動小数点型の動作方法のセマンティクスが変更されました。言語が一貫してそれらをサポートしていれば8087セマンティクスは非常に素晴らしかったでしょうが、関数f1()、f2()などがtypeを返すfloat場合、多くのコンパイラ作成者はそれを引き受けてlong double64ビットdouble型のエイリアスを作成しますコンパイラの80ビット型ではなく(80ビット変数を作成する他の手段を提供しません)、次のような任意の評価を行います。

double f = f1()*f2() - f3()*f4();

次のいずれかの方法で:

double f = (float)(f1()*f2()) - (extended_double)f3()*f4();
double f = (extended_double)f1()*f2() - (float)(f3()*f4());
double f = (float)(f1()*f2()) - (float)(f3()*f4());
double f = (extended_double)f1()*f2() - (extended_double)f3()*f4();

f3とf4がそれぞれf1とf2と同じ値を返す場合、元の式は明らかにゼロを返すはずですが、後者の式の多くはそうではないことに注意してください。これにより、最後の定式化は一般に3番目の定式化よりも優れていたとしても、拡張ダブルタイプを適切に使用したコードでは8087の「余分な精度」を非難することになりました。

その間、Intelは言語の(残念ながら)中間の結果をオペランドの精度に丸める傾向にある(IMHOの不幸な)傾向に対応しました。中間計算の精度。


この投稿には既に上記の回答があります。彼らは1つにマージできる/すべきである回答ですか?

@MichaelT:私はそうは思いません。1つはスタック設計をカバーし、もう1つは浮動小数点セマンティクスをカバーしています。
supercat

念のため。個人的には、1つのより強力な回答(ヘッダーを使用してセクションを区切る)を作成することは可能だと考えていますが、それは私の考えです。ヘッダーを使用して、各回答部分のアドレス(## How the stack changed the processorおよび## How floating point changed the processor)を上部で明確に識別することで、読者がそれを読むときに適切なマインドセットを取得し、回答または再投稿に気が抜けているとは思わないようにすることができます同じ(r同様)答え。

@MichaelT:2つの答えは十分にばらばらなので、別々に投票する必要があると思います。80486は、以前に8087/80287/80387によって実行されていた機能を吸収しましたが、8086と8087は、ほぼ独立したアーキテクチャを持つ別個のチップとして設計されました。両方とも共通の命令ストリームからコードを実行しましたが、それは8086が特定のバイトシーケンスをデータバスを無視しながらアドレス読み取り/書き込み要求を生成する要求として処理し、8087が進行中の他のすべてを無視することで処理されました。
supercat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.