* プリプロセッサでアセンブラを改善する
-(by [[K]], 2025.09.03)
** (0) はじめに
-先日、 https://github.com/buntan-pc/buntan-pc/wiki/ADR-3 を読みました。
-ここには、スタックから2つの値をPOPして、それを乗算して、結果をPUSHするという「mul」命令を考えたとき、それをmulの1語では書けずに4命令になってしまうことが、出力結果の可読性を下げていて、デバッグで不利だという見解が書かれています。・・・確かにそれはそうだよなあと思いました。
-これを何か簡単な方法で(=CPUをFPGAで作り直すとかじゃなくて)解決できないかなと考えて、Cコンパイラのプリプロセッサを使えばいいかなと思いました。
-ここでは、その思い付きに関する話を書きます。
** (1)
-とりあえず、以下のようなテキストファイルを作りました。
-test.c
#include "asmcpp.h"
#define t dword [ebp+16]
#define u dword [ebp+20]
MUL32(t, 2, 3); // こんな感じで書けたらいいよねー.
ADD32(u, 1, t);
#undef t
#undef u
-asmcpp.h
#define ADD32(z, x, y) \
mov eax,x; \
add eax,y; \
mov z,eax;
#define MUL32(z, x, y) \
mov eax,x; \
imul eax,y; \
mov z,eax;
~
-これを以下のコマンドラインで変換してみました。
prompt>gcc -E -o out.txt test.c
-out.txtはこうなっていました。
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
# 1 "asmcpp.h" 1
# 2 "test.c" 2
mov eax,2; imul eax,3; mov dword [ebp+16],eax;;
mov eax,1; add eax,dword [ebp+16]; mov dword [ebp+20],eax;;
-うーん、そうか、プリプロセッサだと改行が消えちゃうわけですね。セミコロンを改行に置換するような簡単なフィルターを書く必要はありそうです。あと#で始まる行は消してしまえばいいでしょう。
-結構めんどくさい気もしたので、自作のコンパイラを作るときに、その出力部に(この前に作った)自作のプリプロセッサと改行置換フィルターを付けて、どのレベルで出力するかを選べるようにすればいいかもしれません。そうすればデバッグははかどりそうです。・・・まあ中間ファイルがたくさんできることを厭(いと)わなければ、全部別々に作ってもよいですが・・・。
** (2)
-これって、 MUL32(t, 2, 3); とか ADD32(u, 1, t); の部分はほぼCPUに依存してないので、それ以外のところを直すだけでいろんなCPUに簡単に対応できそうです。それは楽しいかもしれない!
-今回の例はレジスタマシン風な命令を整備しましたが、もちろんスタックマシン風の命令整備することもできます。
-ちなみに今回の test.c の内容は[[p20250815a]]の(2-1)の出力結果を参考に作りました。
-[Q] なぜCコンパイラのプリプロセッサを使ったの?アセンブラにもマクロ機能はありそうだから、それを使えばいいじゃん!
--[A] それはそうなのですが、アセンブラのマクロ機能はアセンブラごとにばらばらで、何ができて何ができないか自明ではないので、それならみんな知っているCのプリプロセッサでやってみたのです。
--だからアセンブラのマクロ機能が好きなら、もちろんそれでやっても何の問題もないです!
-[Q] なんで test.c っていうファイル名なんだよ!これはC言語じゃないよね!プンプン!!
--[A] す、すみません。たとえば.txtとかにするとgccがプリプロセッサを通してくれなくて・・・。いやいろいろオプション付ければ任意の拡張子に対してプリプロセッサを適用できそうなのですが、今回の時点でそこまで頑張って話をややこしくするのは本意ではなく・・・。