register指定子

引用from: http://www.geocities.jp/ky_webid/c/051.html

registerを付けた変数には、高速にアクセスできるようにコンパイラに要求を出します。要求を出すだけであって、コンパイラがそれに従うかどうかは分かりませんし、どのような方法で高速アクセスを実現するかも分かりません。通常は、CPUに存在するレジスタという記憶領域に変数の値を割り当てます。レジスタはメモリよりも高速にアクセスできます。ここからregisterという名前になりました。

この指定子も、わざわざ付ける必要はありません。なぜなら、コンパイラは自動的にこのような最適化を施してくれるからです。つまり、registerを付けても高速になるとは限らないし、付けなくても高速になるかも知れないということです。

なお、registerを付けた変数のアドレスは取得できません。アドレスとは、メモリ上の番地であり、レジスタに番地はないからです。よって、ポインタ変数にregisterは付けられません。また、グローバル変数や静的変数に registerを付けることはできません。レジスタの個数には制限があり、これらの変数はプログラム実行中、常に存在しなくてはならないため、レジスタが埋まってしまうからです。

以前、O(最適化オプション)をつけないでgccコンパイルした単純なテストプログラムのバイナリと、そのプログラムのアセンブルソースを自分で改良したバイナリの速度比較を行いました。
http://ikda.net/fswiki/wiki.cgi?page=%B7%D7%BB%BB%B5%A1%B2%CA%B3%D8%A4%E2%A4%C9%A4%AD
そのときは2倍くらい早くなったわけです。

妄想の域を出るものではありませんが、レジスタと一次キャッシュの速度の差ということでしょうか?

で、なんでこのregister指定子の話にまたなったのかというと、MySQLのparserのコード中に、register指定子が使われているのを見つけたからです。

昨日でてきたsql_yacc.ccの以下のコードですが、

  case 800:
#line 4373 "sql_yacc.yy"
    {
        if (!(yyvsp[-2].symbol).symbol->create_func)
        {
              my_error(ER_FEATURE_DISABLED, MYF(0),
                       (yyvsp[-2].symbol).symbol->group->name,
                       (yyvsp[-2].symbol).symbol->group->needed_define);
          YYABORT;
        }
        (yyval.item)= ((Item*(*)(void))((yyvsp[-2].symbol).symbol->create_func))();
      }
    break;

parserのコードではこの"case 800:"のように、かなり巨大な"switch-case"文が使用されています。となると結構、このswitch対象の変数"yyn"にアクセスが集中すると思うのですが、

  register int yystate;
  register int yyn;

こんな感じでregister付きの宣言をしています。



なんだかんだで、parserのコード読書率が上昇中。。。いちばん手を出したくない部分なんだけど(涙 しかしここを見ないと処理の振り分けが分からん=3 SPとかSPとかSPとかw

とかいう前置きをしたところで、今日言いたいのは〜〜〜
ビルコレさん、新色のニンテンドーDS Lite欲しい!