目次: GCC
以前(2020年3月27日の日記、2020年3月28日の日記、2020年3月29日の日記参照)ベクトルレジスタを扱えるようにした際に、下記の問題が残っていました。
1つ目の問題に取り組んでいきたいと思います。RISC-V 32の場合、intの変数は32bit整数のデータ型として扱われます。GCC内部の表現(RTL)ではSImodeというマシンモード(※)で表されます。他の大きさのデータ型を示すマシンモードも当然存在していて8, 16, 64bit整数はそれぞれBImode, HImode, DImodeで表されます。
普通の型に対応するモードはGCCが定義済みですが、ベクトル型を表すモードは標準では存在しないため、自分で新規に定義する必要があります。
(※)マシンモード(Machine Mode)については、GCC Internalsの14.6 Machine Modesに簡単な説明と標準的なモードの一覧が載っています。これによればSIはSingle Integerの略らしいです。変な名前だなあ。
以前(2020年3月14日の日記参照)説明したとおりですが、軽くおさらいすると、標準的なマシンモードはgcc/machmode.def、アーキテクチャ固有のマシンモードはgcc/config/arch/arch-modes.defにあります。例えばRISC-Vならgcc/config/riscv/riscv-modes.defです。
現在のところRISC-V固有のマシンモードは1つしか定義されていません。
FLOAT_MODE (TF, 16, ieee_quad_format);
このファイルにベクトル型を表すマシンモードを追加します。
VECTOR_MODE (INT, SI, 8);
VECTOR_MODE (INT, SI, 16);
VECTOR_MODE (INT, SI, 32);
VECTOR_MODE (INT, SI, 64);
とりあえず整数(INT, SI)が8, 16, 32, 64(それぞれ32, 64, 128, 256バイト)個連結されているデータ型を想定して作りました。ベクトル型を語る上では浮動小数点型も大事ですが、とりあえず今回は整数型のみを定義しています。
マシンモードを正しく追加できたか確かめる方法は色々あるのでしょうけど、個人的に簡単だと思うのは一旦ビルドしてしまう方法です。
GCCをビルドするとビルド用のディレクトリ(以降build_gccと呼びます)に、モードが全部書いてあるヘッダinsn-modes.hが生成されます。生成されたヘッダを検索すれば一発です。
// gcc/build_gcc/insn-modes.h
enum machine_mode
{
E_VOIDmode, /* machmode.def:189 */
#define HAVE_VOIDmode
#ifdef USE_ENUM_MODES
#define VOIDmode E_VOIDmode
#else
#define VOIDmode ((void) 0, E_VOIDmode)
#endif
E_BLKmode, /* machmode.def:193 */
#define HAVE_BLKmode
#ifdef USE_ENUM_MODES
#define BLKmode E_BLKmode
#else
#define BLKmode ((void) 0, E_BLKmode)
#endif
...
E_V32SImode, /* config/riscv/riscv-modes.def:26 */
#define HAVE_V32SImode
#ifdef USE_ENUM_MODES
#define V32SImode E_V32SImode
#else
#define V32SImode ((void) 0, E_V32SImode)
#endif
E_V64SImode, /* config/riscv/riscv-modes.def:27 */
#define HAVE_V64SImode
#ifdef USE_ENUM_MODES
#define V64SImode E_V64SImode
#else
#define V64SImode ((void) 0, E_V64SImode)
#endif
...
新たなマシンモードV64SImode(SIが64個連結されたデータ型)が追加されたことがわかると思います。コメントにマシンモードの定義されている場所も書かれていて、とても親切です。
ほぼ全域に渡って意味不明コードだらけのGCCでは珍しい部類の、わかりやすさ&親切さです。自動生成コードには気を使っているんでしょうか?他のところもこれくらい親切だと嬉しいんですけどねえ。
今年のヤマザキ春のパン祭りは、2枚もゲットできました。
去年は品川勤務かつコンビニ昼飯がメインだったので、ヤマザキパンを買う機会がほぼなく、お皿をもらえるほど点がたまりませんでした。今年はCOVID-19による在宅勤務で、近所のスーパーでパンを買う機会が大幅に増えたため、2枚も手に入ったわけです。在宅勤務の意外な効果です。
コンビニに行かない人にとっては意外かもしれませんが、コンビニはヤマザキパンをほとんど置いていません。自社のプライベートブランドのパンばかりです。10年位前は他社のパンも置いていたんですが、今やコンビニは9割方がプライベートブランドのパンです。
コンビニのプライベートブランドのパンは、大手メーカー(ヤマザキパン、敷島製パン、フジパンなど)が作っていますが、コストの都合か何だか知りませんが、味に劣る気がします。好みの問題なのかな……?
パン祭りのお皿、裏側に何か書いてるなーと思って写真を撮ってみました。
ちょっと見づらいので文字に起こすと、
ARTICLE YAMAZAKI
MADE IN FRANCE
ZENMEN
BUTSURIKYOUKA
GARASU
「全面物理強化ガラス」ってローマ字で書いてありますね。フランス製なのに何でローマ字?フランス語で書かれても読めないから?
見ていて素朴な疑問が沸きました。あえて「全面」と強調する理由はなんでしょうね?皿のように厚みのない製品で「片面」物理強化ガラスにすることは可能?可能だったとしてもやる意味がある?
Pythonの文字列置換は "string".replace() ですが、正規表現ライブラリreだと、なぜかre.sub() です。同じ機能なのに、APIの名前も、引数の指定順序も違います。どうしてこうなった。
改定の度に魔界化するC/C++ に比べると、Pythonは明瞭に思えます。とはいえPythonも何だかんだ長い歴史ですし、祓いきれない闇があるんでしょうねえ。
メモ: 技術系の話はFacebookから転記しておくことにした。
目次: Kindle
KindleのアプリはKindle Fire版、Android版、PC版など、いくつか種類があります。普段使っているのはKindle FireとKindle for PCです。どうもKindle for PCのダウンロードが遅い気がします。
Kindle Fireも決して速いとは思いませんが、大抵はマンガ1冊が1〜2分でダウンロードできているので、5Mbpsくらいは出ているんじゃないかと思います。
Kindle for PCはかなり遅い(1〜2Mbpsくらい、日によって違う)です。同じネットワークを使っているのに、差が出るものですかね?PC向けだけ帯域ケチるとか、そんな面倒なことしないよなあ?うーん?
Kindle Fire HDのアプリはたまにアップデートされて動きが変わります。今年の頭くらいだったか?覚えてないですけど、また動作が変わりました。
新たなバグは再現率100%です。再現方法も簡単です。
この順に操作したとき、本来は本の一覧が出なければなりませんが、グループ化された本が再表示されてしまいます。明らかにバグってます。
このバグは、ユーザー側の操作で回避可能です。
ユーザーの操作に影響が出るバグですし、テスターに触らせたら数分で見つけそうなのにね?KindleってUIのテストしてないのかなあ??
目次: RISC-V
マクロの名前にTypoと思しきものがあったので、riscv-binutils-gdb(サイトへのリンク)にPull Requestをしてみました。
RISC-V向けのgasの実装では、命令に対応した名前のマクロがあります。
//opcodes/riscv-opc.c
//通常は命令の名前からドットを除いて、大文字にした名前
// vadd.vv -> MATCH_VADDVV
{"vadd.vv", 0, INSN_CLASS_V, "Vd,Vt,VsVm", MATCH_VADDVV, MASK_VADDVV, match_opcode, 0 },
{"vadd.vx", 0, INSN_CLASS_V, "Vd,Vt,sVm", MATCH_VADDVX, MASK_VADDVX, match_opcode, 0 },
{"vadd.vi", 0, INSN_CLASS_V, "Vd,Vt,ViVm", MATCH_VADDVI, MASK_VADDVI, match_opcode, 0 },
//Reduce系の命令だけ名前が違う
// vredsum.vs -> MATCH_VREDSUMV"S" のはずなのに、MATCH_VREDSUMV"V" になっている
{"vredsum.vs", 0, INSN_CLASS_V, "Vd,Vt,VsVm", MATCH_VREDSUMVV, MASK_VREDSUMVV, match_opcode, 0},
パッチの中身は簡単で、ベクトル命令の一部で、命令の名前とマクロの名前が違っていたので修正しただけです。この手の間違いがいくつあるか分からなかったので、ちょっとしたPythonスクリプトを書いてチェックしました。
#!/usr/bin/python
import re
import sys
fname = sys.argv[1]
f = open(fname, 'r')
line = f.readline()
while line:
if not line.startswith('{"'):
line = f.readline()
continue;
line = line.strip().replace('}', '')
line = re.sub('\{"([^,]*)",', r'\1,', line)
line = re.sub('".*",', '', line)
line = re.sub(' *', '', line)
items = line.split(',')
insnOrg = items[0]
insn = items[0].upper()
classInsn = items[2]
matchInsn = items[3]
maskInsn = items[4]
aliasInsn = items[6]
if not classInsn.startswith('INSN_CLASS_V'):
line = f.readline()
continue;
if not matchInsn.startswith('MATCH_') or not maskInsn.startswith('MASK_'):
line = f.readline()
continue;
if aliasInsn.startswith('INSN_ALIAS'):
line = f.readline()
continue;
insn = insn.replace('.', '')
matchInsn = matchInsn.replace('MATCH_', '')
maskInsn = maskInsn.replace('MASK_', '')
if matchInsn != maskInsn:
print("MATCH != MASK: {:s} != {:s}".format(matchInsn, maskInsn))
if insn != matchInsn:
print("INSN != MATCH: {:s} != {:s}".format(insnOrg, matchInsn))
line = f.readline()
条件を適当に継ぎ足して書いたのと、Pythonの経験値が低いのが相まって、エレガントさの欠片もないですね。仕方ない。実行結果はこんな感じです。
$ ../checker.py opcodes/riscv-opc.c INSN != MATCH: vzext.vf2 != VZEXT_VF2 INSN != MATCH: vsext.vf2 != VSEXT_VF2 INSN != MATCH: vzext.vf4 != VZEXT_VF4 INSN != MATCH: vsext.vf4 != VSEXT_VF4 INSN != MATCH: vzext.vf8 != VZEXT_VF8 INSN != MATCH: vsext.vf8 != VSEXT_VF8 INSN != MATCH: vredsum.vs != VREDSUMVV INSN != MATCH: vredmaxu.vs != VREDMAXUVV INSN != MATCH: vredmax.vs != VREDMAXVV INSN != MATCH: vredminu.vs != VREDMINUVV INSN != MATCH: vredmin.vs != VREDMINVV INSN != MATCH: vredand.vs != VREDANDVV INSN != MATCH: vredor.vs != VREDORVV INSN != MATCH: vredxor.vs != VREDXORVV INSN != MATCH: vwredsumu.vs != VWREDSUMUVV INSN != MATCH: vwredsum.vs != VWREDSUMVV INSN != MATCH: vfredosum.vs != VFREDOSUMV INSN != MATCH: vfredsum.vs != VFREDSUMV INSN != MATCH: vfredmax.vs != VFREDMAXV INSN != MATCH: vfredmin.vs != VFREDMINV INSN != MATCH: vfwredosum.vs != VFWREDOSUMV INSN != MATCH: vfwredsum.vs != VFWREDSUMV INSN != MATCH: vcompress.vm != VCOMPRESSV
明らかにTypoに見えるのはvred/vfred/vcompress系の命令で、vsとvvを取り違えています。
微妙なところなのはvzextです。他はドットを除いた名前なのに、vzextだけドットをアンダースコアに置換した名前です。ルールに一貫性が無いだけか、Typoか、どちらとも言い難いため、今回出したPull Requestでは修正していません。
リポジトリを見ていてちょっと気になったのはSiFiveの人以外、変更がほとんどないことです。著名プロジェクトでは珍しいです。もしかするとGitHubでPull Requestを受け付けてない(※1)可能性があります。
変更を提案するのはここじゃないとか、そもそも変更は受け付けてませんとか、何でも良いので反応があると嬉しいですね、週明けまで待ちましょうかね……。
(※1)本家および開発の場がGitHub以外に存在していて、GitHubをミラーにしているプロジェクトの場合、GitHub上で何か言っても無視されることがあるようです。
Splatoon 2のガチマッチ(Cランク)の難易度が下がった気がします。
1〜2か月前は、20kill対0killで負けたり、1分でノックアウトされたり、超フルボッコで負けまくるのが当たり前で、すっかりやる気がなくなっていましたが、今日久しぶりにやったら一度も負けず、あっさりC+ ランクになりました。
アクションゲームの腕は1か月やそこらで急に上達しないので、私が上達したというよりも、絶対勝てないおかしいレベルのプレーヤーとマッチする割合が減った、そんな感じです。
Stay Homeとかゴールデンウイークとかで、Splatoon 2のプレーヤー人口が盛り返して、初心者クラス(C-〜C+ ランクあたり)に合う人が増えたんじゃないかと推測しています。
最初からこのくらいの難易度だったら、ガチマッチ嫌いにならずに済んだんですけど、すっかりガチマッチ嫌いになってしまった(レギュラーマッチは好き)ので、もう遅いんだよな〜……。
目次: C言語とlibc
C言語のマクロによる置換を、循環参照させたらどうなるでしょう?
A B C D
#define A B
A B C D
#define B C
A B C D
#define C A
A B C D
結論から言うと問題ありません。下記のような結果になります。
A B C D
B B C D
C C C D
A B C D
4つ目の結果は、置換前のA B C Dと何も変わっていないように見えますが、実はそうではありません。下記のように定義するとわかります。
A B C D
#define A 1 B
A B C D
#define B 2 C
A B C D
#define C 3 A
A B C D
A B C D
1 B B C D
1 2 C 2 C C D
1 2 3 A 2 3 1 B 3 1 2 C D
4つ目の結果の「A」を例にとると、A -> B -> C -> Aと3回のマクロの置換が行われた結果、Aに戻っているわけです。#define A Bのマクロは1度しか適用されないようです。
C言語の仕様(C11 final draft (N1570) - 6.10.3.4 Rescanning and further replacementの第2項)を見ると、
2
If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file's preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.
(直訳)
2
置換されるマクロの名前がreplacement listのスキャン中に見つかった場合(ソースファイルの残りの前処理トークンは含まれません)、そのマクロは置換されません。 さらに、入れ子になった置換が、置換されているマクロの名前に遭遇した場合、それは置換されません。 後にそのマクロ名の前処理トークンが置換されていたであろうコンテキストで(再)検査されても、これらの置換されていないマクロ名の前処理トークンはそれ以上の置換はできなくなります。
正直言って何言ってんだお前……?って感じがしますけども、平たく言うと同じマクロを2回適用しない、ように読めます。
下記のように同じマクロで何度も置換できそうなマクロを定義してみます。
#define A B C
#define B C A
#define C A B
A B C D
A B A A C A B C B B A B C A C C B C D
1つ1つのトークンがどのマクロで展開されているか図示します。
複雑に見えますが、どのトークンを見ても同じマクロを2回適用されたものはないことがわかります。
しかし関数型マクロの場合は、不思議な挙動を示します。
#define F(a) a G
#define G(a) a F(a)
F(7)(8)(9)
7 8 8 G(9)
展開の様子は下記のようになると思われますが、
どうして7 8 8 G(9) で展開が終わるのかが良くわかりません……。マクロF(a) を2回適用しない、というルールならば、7 8 F(8)(9) で止まらなければおかしいように思いますが、結果を見るとなぜかF(8) も展開されています。
今、使ってるノートPC(ThinkPad E480カスタムオーダー)には、Intelのグラフィクスと、Radeon RX 550が搭載されています。
Radeon RX 550はモバイル用としては結構強力で、主にゲームの時に助かっているのですが、Radeonを使ってゲームをしばらくやっていると、本体が触れないくらい熱くなり、しまいに熱暴走でクラッシュしてしまいます。
せっかくカスタムオーダーで追加したのに微妙な奴だな〜。
このGPUはもうひとつ変なところがあって、デバイスマネージャでRadeon RX 550を「無効」にしてPCを再起動すると、冷却ファンが唸り続けます。
CPU利用率は極めて低いままにも関わらず、冷却ファンが全力稼働しているので、ファンの制御がおかしくなっているように思います。GPUの負荷を勘違いしているのだろうか?
プロセスを片っ端から終了させても収まらなかったところをみると、恐らくドライバが変なところにハマっている?のでしょうか。
デバイスを有効にするか、有効にしたあとに再度無効にすれば、CPUファンは静かになりますが、なんだか挙動不審ですよね……。
目次: Kindle
Amazonでハンダごて一式を購入しました。
まず、ハンダが来ました。
次に、ハンダこて台、ハンダ吸い取り線が来ました。
肝心の、ハンダごてが来ません……(後日、ハンダごても届きました)。
Amazonは一括で注文できますが、発送元の違いで一括で発送されないことは良くあります。たまに不思議な順番で送られてきてちょっと面白いですよね。
メモ: 技術系の話はFacebookから転記しておくことにした。
目次: ゲーム
昨日(2020年4月29日の日記参照)に引き続きTransport Fever 2の基本である、生産量について紹介します。画像をできるだけ使うようにしました。ゲームの雰囲気を感じてもらえたら嬉しいです。
生産量の概念は、私が最初に躓いて一番訳の分からなかったところです。うまく説明できると良いんですけど。
Transport Fever 2のフリープレイで出現する生産者、消費者は5段階に分類できます。カテゴリの正式名がないため、私が適当に名付けています。間違っていたらごめんなさい。
図の見方を一応説明しておくと、食料加工プラントの場合、農場から「穀物」を2つ運ぶと、1つの「食料」が生産される、このように見ます。生産がダントツで面倒くさいのは「商品」ですね。
経路がシンプルな「穀物」→「食料」にも罠があります。施設の生産キャパシティは基本的に最大400ですが、なぜか農場だけ200 しかありません。レベル最大の食料加工プラントで食料を400生産するには穀物が800必要ですから、農場4つから穀物を運ばなければなりません。
ちなみに…、「製油所」が2つ出てくるのは誤植ではありません。「製品」工場が「商品」を作るのも、「工場」と「プラント」が混ざっているのも誤植ではありません。Transport Fever 2の日本語はポンコツなので、突っ込み出すとキリがないです。
中間と最終生産を担う工場にはレベルがあり、生産上限がレベルで決まります。レベルは各施設をクリックすると出てくる概要に表示されています。
ただまあ、工場のレベルを上げるぞ!!と思って上げることはあまりなくて「たくさん原料を運び込んで」「生産したものを全部消費」しているうちに、勝手に上がっていることが多いです。
生産と消費がTransport Fever 2で一番わかりにくい概念だと思います。生産施設は常に「必要とされた分」しか作りません。私は最初、この概念が全く分かりませんでした。
先日作った経路で説明しましょう。森から製材所への運送経路を1つだけ作りました。生産(森)と消費(製材所)の関係はこうなります。
基本的に消費側(製材所)の要求数 = 生産側(森)の生産数(2番目の「輸送」の数字)になります。正確に言えば、下記のロジックで決まります。
消費側は繋がっている生産側「全て」に要求するのが、わかりにくいんですけど、結構大事です。
もし製材所レベル1に、森A、森Bを2つ繋いだとすると、森2つに対し「合計400の木材が要求」され、森の生産力が余ります。すると、森Aは100、森Bは300のように分散して生産し始めます。
このダイアログの情報は難しい部類ですが、日本語が完全に本当にポンコツです、全く説明になっていません。特に「輸送」を違う意味で2つ並べた人は何を考えているんでしょう?どう見てもおかしいでしょう??
これはわかりにくくて紛らわしい数字が表示されることが多いので、説明しておきます。トラック駅をクリックして路線をクリックすると、路線の情報が表示されます。
ほとんど見ればわかる系の情報なのですが「割合」は注意が必要です。数字は路線の年間輸送力を意味しています。これもポンコツ翻訳のひとつですね……。この路線は400の木材を森から製材所に運ぶために作ったことを思い出せば、400前後の輸送力にしておくと無駄がないことが分かると思います。
路線のコースを変えたりトラックの種類や数を変更すると、すぐに年間輸送力の数字が変化します。例えばこの路線では、トラックを1台から12台にすると400くらいの値が表示されました。
しかしながら、この数字は実際の輸送力とかけ離れている場合があります。ある程度待つと実情に近い値に補正されます。この補正がかなり劇的で、路線の変更直後は400だったのにしばらく経つと480など大幅に増えたり、逆に激減したりすることが多々あって気づかないうちに輸送力が不足したり、無駄になったりします。
ですから路線の輸送力を変更したときは、ちょっと時間をおいてから再チェックすることをお勧めします。
私の個人的な感覚では、トラックは最初の数字が低めに出る傾向(=後で増える)、鉄道と船舶は最初の数字が高めに出る(=後で減る)傾向があるように感じます。
目次: ゲーム
昨日(2020年4月28日の日記参照)に引き続きTransport Fever 2の基本となる片道の輸送について紹介します。画像をできるだけ使うようにしました。ゲームの雰囲気を感じてもらえたら嬉しいです。
道路で繋いだだけでは貨物は輸送されません。路線を作成して、どこからどこへ輸送するか決めます。
「森(右下)」から「製材所(左上)」に木材を運びたいので、2つのトラック駅を路線に追加します。トラックでも何でもそうですが、輸送車両は「終点」までたどり着いたら、次は「始点」に戻ります。例えば経路A, B, C, Dを作ったら、A B C D A B C D ... の順に巡回します。
今回は2駅しかないピストン輸送ですので、始点と終点はどちらが先でも気にしなくて良いです。
最後にトラックを購入、路線に配備します。発着所をクリックするか、車両マネージャから発着所を選択します。大抵の場合は前者の方が楽です。
トラックを購入します。車両マネージャーから購入画面を出して、Opel Blitz防水布トラックを購入します。目的の貨物(木材)が搭載できれば何でも良いです(Benz製防水布トラック、Saurer C Type防水布トラックなどでも大丈夫)。
運送車両の種類によって、積めるものに制限がありますので、車両購入の際は「貨物の種類」をチェックしましょう。例えばOpel Blitzタンクトラックは石油や燃料のような液体しか積めず、木材を運ぶことはできません。
輸送手段 | 即時性 | 輸送力 | 貨物の種類制限 | 備考 |
---|---|---|---|---|
トラック | ×〜〇 | ×〜〇 | 自由 | 時代が進むと性能が桁違いに上がる、街のマイカーに邪魔される |
船舶 | × | △〜〇 | 割と自由 | 時代が進むと性能が上がる、石油系とその他に分かれていることが多い |
鉄道 | △〜〇 | △〜〇 | 厳しい | 時代が進むと性能が上がる |
航空機 | 〇 | × | 自由 | 使用可能になる年代が遅い |
各輸送手段の違いは上記の通りです。トラックは1850年代は遅いし輸送力も低いですが、時代が進むと割と万能になります(スピードが速く「すべての貨物」が積める)。ただし道路の他の車(マイカー、バス)により、邪魔される点には注意しないといけません。
個人的なオススメは、鉄道とか船舶とか癖の強いものに挑む前に、1950年(良いトラックが使える)開始で、トラックを使った輸送の仕方を色々試すことです。ストレスも少ないし、慣れるのも早いと思います。キャンペーンの最初の方をやってみるのも一興ですね。
購入したトラックを、先ほど作成した路線に配備すると、木材の輸送が開始されます。森の近くのトラック駅を眺めると、木材がどんどん積まれていく様子が見えるはずです。
無事、車両の配備まで成功したら、こんな風になるはずです。
上記はトラック1台だと寂しいので、トラックを10台ほど同じ路線に配備した状態です。せっせと働くトラックを眺めるのは楽しいですよね。
森のトラック駅に何もなく、トラックの積み荷がずっと空っぽの場合は、下記をチェックしてみてください。製材所側のトラック駅には何もないのが正しいです。
このゲームの特徴として「生産施設は、消費施設へ貨物の運送経路が確立するまで稼働しない」点が挙げられます。さすが輸送ゲームらしい仕様ですね。
今回やったことは、上記の5つです。どれが欠けても生産施設は稼働しません。
< | 2020 | > | ||||
<< | < | 05 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |
合計:
本日: