コードサイズが肥大化した原因

プログラムにある改造を施していたらビルドが通らなくなったと相談があり、

リンカでのエラーで、おそらくプログラムサイズの問題なんだろうなと、

調べてみたら異常にコードサイズが巨大な関数があって、

一体何が原因かと思ったらバイトオーダーを入れ換えるマクロのせいだった。


こんなやつね。

#define SWAP32(v) (((v) & 0xff000000u)>>24)|(((v) & 0xff0000u)>>8) | \
                   (((v) & 0xff00u)<<8)|(((v) & 0xffu)<<24))

こんな処理が愚直に展開されてしまっていたと。

これが何回も何回も出てくる関数がとんでもないサイズに肥大化していたと。

で、さすがにおかしいだろということで確認したところ、

最適化レベルをNoneにしていたらしく、それも相まってすごいサイズになってしまったらしい。


確かにマクロというのは使う場所に都度コードを展開するというものなので、

何度も何度も使うとコードサイズが肥大化する原因にはなりうる。

ただ、コンパイラの最適化が期待できる部分もあり、

上記のマクロにしても a=BSWAP(0x12345678); のような使い方だと、

定数演算はコンパイラで済ませて、a=0x78563412; に相当する処理になるなど、

マクロを使うことによる特有のメリットがあると言うこともまた1つの側面である。

そこの見極めが必要だったんじゃないのというのは1つありますが。


そもそも冒頭に書いたような処理は専用の命令を持ってるCPUが多いわけで……

#define BSWAP32(v) ({ unsigned int r; \
__asm__("rev %0, %1" :"=r" (r):"r" (v)); r; })

のような書き方の方がよかったという説はある。

コンパイラの最適化でこういう置換をしてくれることもあるが、

最適化レベルを下げていたのでそういうのも期待できなかったと。

この話にはさらに続きがあるんだけど、それは書けない話なので書かない。


コードサイズの肥大化という形で問題が顕在化したわけだけど、

よくよく考えてみるとコードサイズが大きい=実行時間が長くなるという構図である可能性も高く、

新規に挿入したマクロでコードサイズが激増したということは、それだけ実行時間が増えるんだろうなと。

コードサイズの増加だけの問題ならばマクロから関数呼び出しに変える方法もあり、

コードサイズへの影響はかなり軽減できることにはなる。

ただ、実行時間の増加という観点ではほぼ変わらないわけである。

そう考えると正直どうなのかなと思うところもある。


バイトオーダーの変換に限らず、いろいろな処理をマクロでやっていて、

ほぼコンパイラで静的に処理されるだろうと期待しているものも多いが、

中にはけっこうなコードサイズの処理になっているものもあるのかもしれない。

かなり衝撃的な話でしたね。