8/28 (金)
[CPU] System/370 の命令の条件コードの覚え書き
System/370 や 390 の命令はその演算結果によって、 条件コード(Conditional Code; CC) が設定される。 これは i386 の FLAGS のような効果を持って 主に条件分岐の入力として使用されるのだが、 現代の CPU アーキテクチャから見るとかなり歪な変化をする箇所があるよなぁ…
論理減算命令(SUBSTRACT LOGICAL; SL)
S/370 の論理加算命令(ADD LOGICAL)は二つのオペランドを符号なし整数とみなして加算を行ない、 その結果が桁溢れを起こすと carry と判定している。 そして結果に応じて CC が変わる。
一方、SL 命令も二つのオペランドを符号なし整数とみなして減算を行ない、 その結果が桁落ちを起こすと carry と判定している、、、 ようなのだが同じ値を引いて結果が 0 となる演算は carry だと判定されている。 i386 も sub 命令の演算結果が Carry Flag (CF) に反映されるが、 同じ値を引いて結果が 0 は CF=0 になり non-carry と判定される。
こういう判定になってしまうのは、
S/370 側の論理減算が A - B
を A + ~B + 1
と計算しているためらしい。
一方、S/370 の算術減算命令の方は CC で overflow を判定するが、 同じ値を引いて結果が 0 なら non-overflow と判定される。
算術左シフト(SHIFT RIGHT arithmatic; SRA)
算術左シフトは通常の論理左シフトと異なり、 符号ビットが変化しないシフトである。 C 言語で書くと以下のようなイメージになる。
uint32_t shift_right_arithmatic(uint32_t value, int shift) { union { struct { uint32_t value : 31; uint32_t sign : 1; } s; uint32_t v; } sra; sra.v = value; sra.s.sign <<= shift; return sra.v; }
この S/370 の算術右シフトには、演算結果のオーバーフローが定義されている。
i386 のシフト演算の結果はみ出した最後のビットがキャリーフラグに格納されるが、 S/370 の算術左シフトははみ出したビットが符号ビットと異なる場合に、 オーバーフローと定義される。
例えば -2147483648(0x80000000) を1ビットだけ、 算術左シフトとすると下位31ビットが1ビット分左シフトするだけなので 元と変わらず -2147483648(0x80000000) になる。 この演算では 30ビット目の 0 がシフトアウトするが、 シフトアウトするビットは符号ビット 1 と異なるので オーバーフローになる。
算術的に解釈すると、 元の値を符号付き整数と見なした時にシフト演算の結果が 2シフト幅 で割ったものと同じビット表現になっていれば non-overflow、 異なるビット表現になっていれば overflow であろう。
8/14 (金)
[CPU] Long VHPT walker の呪いが再び
IA-64 の Long VHPT walker で再び障害が発生。 どうも VHPT walker が非同期的に動作する条件を誤っていたのが原因のようだ (VHPT は 2006年4月28日、 2006年5月4日、 2009年1月13日)。
Long VHPT モードは名前の通り「ハッシュ」テーブルなのだが、 同一のハッシュ値を持つエントリはテーブル内に1つか置けない。 つまり衝突が起きると古いエントリを捨てて入れ替える必要がある。
ところが VHPT のテーブルは下の図の1エントリ32バイトのデータ構造になっている(「インテル Itanium アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル 第2巻:システム・アーキテクチャ」からの抜粋)。 IA-64 は 32 バイトを不可分に更新する命令がないため、 マルチプロセッサ環境では VHPT を書き換えようとする CPU と、 VHPT walk を行なっている CPU 間の衝突が問題になる。 前述のマニュアルにはマルチプロセッサ時には VHPT エントリの ti ビットを 1 にしてエントリの無効化し、 その後に他のフィールドを書き換え、 最後に ti ビットを 0 にしてエントリを有効化するようにという注意書きがある。
しかし VHPT walker はプリフェッチや RSE などの投機的なメモリアクセスによっても動作しているようで、 シングルプロセッサ構成でも VHPT エントリの衝突が発生しているようだ。 マニュアルに明記されていないのだが、 Long VHPT エントリを更新する場合は シングルプロセッサ構成やテーブルが CPU 毎に独立している場合でも ti ビットを立ててから更新する必要があるらしい。南無三。

8/12 (水)
Word/Excel/PowerPoint Viewer
会社で使っているノートパソコンには Microsoft Office が入っていないのだが、 会議資料が Word だったり Excel のファイルだったりする。 Microsoft から Word/Excel/PowerPoint の閲覧だけができるツールが提供されているので、 そちらを入れて試してみる。
一時期ファイルの閲覧用に OpenOffice を入れていたのだが、 レイアウトが崩れたり図表や相互参照などの表示が狂ったりして問題があった。 Word/Excel Viewer は流石にそのような問題はなく Word/Excel と同じように表示される。
お金がないので当面はこれで凌ぐしかない。
8/11 (火)
[時事] 地震震度6弱
5時7分に駿河湾おきをでマグニチュード6.5の地震が発生した。 寝付けずに起きていたため地震の揺れに直接遭遇した。 川崎のうちのアパートだと8月9日に起きた地震の方が揺れは強かったように思える。
朝出社してみると、 会社は社員の安否確認をしている。 横浜はいいのだが沼津の事業所は結構混乱していたようだ。 とりあえず人的にも計算資源的にも障害は発生していないのでよしとしよう。
8/4 (火)
[CPU] メモリオペランド形式によって x86-64 命令の速度は変わるのか?
x86-64 命令はほとんどの命令がメモリオペランドを採ることができるが、 だいたい以下の5つの形式でアドレスを指定できる (さらにそれぞれの形式でセグメントレジスタ修飾が可能)。
- Base-register
- Base-register. + Displacement
- Index-register * Scale-factor
- Index-register * Scale-factor + Displacement
- Base-register + Index-register * Scale-factor + Displacement
IA-64 の場合は ld/st 命令に指定できるメモリアドレスは x86-64 で言う 1. の形式だけだったので大変に便利である。 ただ複雑なメモリオペランドは簡単なメモリオペランドよりも 命令の実行レイテンシが大きいのではという不安が残る。
そこで以下の各命令をループしたアセンブラコードを実行してサイクルを測ってみたが、 Intel の NetBurst アーキテクチャと Core2 アーキテクチャでは全て同一サイクルだった。
- movq (%rdi), %rdi
- movq (%rdi,%rsi), %rdi
- movq 8(%rdi), %rdi
- movq 8(%rdi,%rsi), %rdi
- movq 256(%rdi), %rdi
- movq 256(%rdi,%rsi), %rdi
メモリオペランドの計算はロードユニットの中で閉じて行なわれ、 しかも1サイクルで完結するようだ。
という事は
leaq 8(%rdi,%rax), %temp movq (%temp), %rax
のようにアドレス計算を分けて書くのは、 素直にメモリオペランドに書くよりも1サイクル損をしているのね。
movq 8(%rdi,%rax), %rax
まあ実際には メモリオペランドによって命令長が長くなると Iキャッシュの効率が変ってくるのでトレードオフがあるだろうね。