自作コンパイラでRISC-VのC言語の基本的な演算子が動くようになりました。
これの続き
こんなCソースで動作確認しています。
int main(void) { putd(2>=4); return 0; }
低レイヤを知りたい人のためのCコンパイラ作成入門に書いてないところ中心にまとめました。
動いた演算子
<< >>
右シフト、左シフトはそのまんまの命令があるので使う。 C言語で負の値の右シフトは処理系依存。符号が残る方が好きなので算術シフト sra を使いました。
| BinOpKind.LShift -> fp.WriteLine " sll a0, a0, a1" | BinOpKind.RShift -> fp.WriteLine " sra a0, a0, a1"
& | ^
これも対応する命令がある。
| BinOpKind.BitAnd -> fp.WriteLine " and a0, a0, a1" | BinOpKind.BitOr -> fp.WriteLine " or a0, a0, a1" | BinOpKind.BitXor -> fp.WriteLine " xor a0, a0, a1"
&& ||
bit演算をした後、結果を0と比較する。 結果が0でなければ1、結果が0ならば0を返す。
| BinOpKind.LogicalAnd -> fp.WriteLine " and a0, a0, a1" fp.WriteLine " snez a0, a0" | BinOpKind.LogicalOr -> fp.WriteLine " or a0, a0, a1" fp.WriteLine " snez a0, a0"
2023/03/15修正 &&は間違っていた。こっちが正解。 一旦両オペランドを0か1にしてからandを取る。
| BinOpKind.LogicalAnd -> fp.WriteLine " snez a0, a0" fp.WriteLine " snez a1, a1" fp.WriteLine " and a0, a0, a1" fp.WriteLine " snez a0, a0"
>= <=
ちょっと頭を使った。 RISC-Vの比較命令は、slt (set lesser than)しかない。 greater thanを使いた時は、左右のオペランドを入れ替える。
問題は>=と<=。引き算して0以上とかで行けるかなと思ってパターソン先生の The RISC-V Readerを眺めていたら、<=は、>の否定なので専用の命令は要らないと書いてあって納得。
seqz a0, a0が、a0が0ならa0を1に、a0が0以外ならa0を0にしてくれる。
| BinOpKind.LesserThan -> fp.WriteLine " slt a0, a0, a1" | BinOpKind.LesserEqual -> fp.WriteLine " slt a0, a1, a0" fp.WriteLine " seqz a0, a0" | BinOpKind.GreaterThan -> fp.WriteLine " slt a0, a1, a0" | BinOpKind.GreaterEqual -> fp.WriteLine " slt a0, a0, a1" fp.WriteLine " seqz a0, a0"
%
これもそのまんまの命令があるので使う。
| BinOpKind.Modulo -> fp.WriteLine " rem a0, a0, a1"
この後
基本的な演算子が動くようになったが、優先順位が全然ついてないので次は優先順位をつけていく。
ソースはここ