Today アクセスカウンター Yesterday アクセスカウンター

ホワット・ア・ワンダフル・ワールド

私は知識に何ものかを付け加え,また他の人々がより多くのものを付け加える手助けをした --- G.H.ハーディ

全記事一覧 << 2008/07 12345678910111213141516171819202122232425262728293031 2008/09 >>

プロフィール

あろは (alohakun)

  • Author:あろは (alohakun)
  • 若槻俊宏 (WAKATSUKI toshihiro)

    連絡先 : alohakun ___at___ gmail.com
    mixi : http://mixi.jp/show_friend.pl?id=182927
    twitter : http://twitter.com/alohakun

    abstract

    プログラミングという人間の知的行為を体系化し,単なる職人芸ではなく,サイエンスにするための研究をしています.

    具体的には,等価変換計算モデルに基づいた,仕様記述からのプログラム合成の研究をしています.

    もっと噛み砕くと,プログラムの正しさをどのように定式化し,どのような枠組みで,どのように変換を進めていけば,正しさを保証したまま,効率的なプログラムを手に入れることができるのか,ということについて研究しています.

    キーワード : equivalent transformation, computation model, programming paradigm, formal specification, program synthesis













    あわせて読みたい


    この日記のはてなブックマーク数


    スカウター : ホワット・ア・ワンダフル・ワールド


    Map









    FC2 BLOG RANKING

FC2カウンター

ブロとも申請フォーム

この人とブロともになる

ぬるぽ

2008/07/09(水) 15:22:05

ずっと勘違いしてたんですけど,mixi のなつさんたんの日記経由できむら(K)さんに教えてもらいました.

C FAQ 5章 ヌルポインター

ポインタの文脈で出てきた定数 0 は,NULL の内部表現が何であれ,かならずぬるぽ扱いされることが規格で保証されているそうな.

ほえー,知らなかった…

次期 C++ 0x では nullptr とかが提案されてるそうです.しかしまぁ,結局後方互換性のために,コンパイラは定数 0 と,環境依存の NULL の定義と,仕様の nullptr 全部を特別扱いしないといけなくなるだけなので,なんだかなぁという気もします.

ところで,手元の NULL の定義はどうなってるんだろうなと.


$ cat null.c
#include
int main() {
int *p = NULL;
}

$ cpp -E null.c
# 1 "null.c"
# 1 ""
# 1 "<コマンドライン>"
# 1 "null.c"
# 1 "/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h" 1 3 4
# 152 "/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h" 3 4
typedef int ptrdiff_t;
# 214 "/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h" 3 4
typedef unsigned int size_t;
# 326 "/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h" 3 4
typedef long int wchar_t;
# 2 "null.c" 2
int main() {
int *p = ((void *)0);
}


C なので見慣れた (void *)0 に.

/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h を見てみると.


/* A null pointer constant. */

#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL /* in case has defined it. */
#ifdef __GNUG__
#define NULL __null
#else /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
#endif /* G++ */
#endif /* NULL not defined and or need NULL. */
#undef __need_NULL


C++ の場合は ((void *)0) をポインタの文脈で暗黙的にキャストできないから,定数 0 にする.

g++ では __null とかいう,謎の予約語が使われるらしい.

gcc-4.3.0/gcc/c-common.h


/* A node for `((void) 0)'. */
#define void_zero_node c_global_trees[CTI_VOID_ZERO]

/* The node for C++ `__null'. */
#define null_node c_global_trees[CTI_NULL]



gcc-4.3.1/gcc/cp/lex.c

static const struct resword reswords[] =
{
...
{ "__null", RID_NULL, 0 },
...

gcc-4.3.1/gcc/cp/parser.c


/* Expressions [gram.expr] */

/* Parse a primary-expression.

primary-expression:
literal
this
( expression )
id-expression

GNU Extensions:

primary-expression:
( compound-statement )
__builtin_va_arg ( assignment-expression , type-id )
__builtin_offsetof ( type-id , offsetof-expression )

C++ Extensions:
__has_nothrow_assign ( type-id )
__has_nothrow_constructor ( type-id )
__has_nothrow_copy ( type-id )
__has_trivial_assign ( type-id )
__has_trivial_constructor ( type-id )
__has_trivial_copy ( type-id )
__has_trivial_destructor ( type-id )
__has_virtual_destructor ( type-id )
__is_abstract ( type-id )
__is_base_of ( type-id , type-id )
__is_class ( type-id )
__is_convertible_to ( type-id , type-id )
__is_empty ( type-id )
__is_enum ( type-id )
__is_pod ( type-id )
__is_polymorphic ( type-id )
__is_union ( type-id )

Objective-C++ Extension:

primary-expression:
objc-expression

literal:
__null

ADDRESS_P is true iff this expression was immediately preceded by
"&" and therefore might denote a pointer-to-member. CAST_P is true
iff this expression is the target of a cast. TEMPLATE_ARG_P is
true iff this expression is a template argument.

Returns a representation of the expression. Upon return, *IDK
indicates what kind of id-expression (if any) was present. */

static tree
cp_parser_primary_expression (cp_parser *parser,
bool address_p,
bool cast_p,
bool template_arg_p,
cp_id_kind *idk)
{
...
/* The `__null' literal. */
case RID_NULL:
cp_lexer_consume_token (parser->lexer);
return null_node;

GCCTB:0CM:0 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

GCC Hacks セミナー資料

2008/06/30(月) 07:59:55

ようやく slideshare にアップロードできました.やっぱり,昨日何回やっても失敗したのは,単にサーバが不調だっただけみたいですね…







ちなみに,当日の ustream 配信が,ここで見られるそうです.

Webcast by Ustream.TV

@noplans さんに教えていただきました.Ruby 札幌 KaigiFreaks 様に感謝です.







ニコニコデビューしました!


GCCTB:0CM:0 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

Write GCC in C++

2008/06/20(金) 13:09:39

Write gcc in C++ (GCC Summit 2008 in otawa) PDF
# GCC Summit に行ってきて興奮冷めやらぬ QLeap さんに twitter でこの PDF を教えてもらったのが,そもそもの関心を持ったきっかけ.

あとの流れは,
Converting GCC to C++
tabesugi.net 2008年 6月 (2)。Jun 19 [Thu] (20:38)
>>はじめてのにき (2008-06-20)
みたいな感じ.

Lisp ってのがあいまいですけど,通常単に Lisp と言ったら,Common Lisp のはず.そして Common Lisp はネイティブコンパイラの方が普通だと思います.

ブートストラップを達成云々は CLISP (バイトコードコンパイラ) じゃなくて,SBCL (CMUCL) のことですかね.SBCL (CMUCL) をビルドするのに SBCL (か CMUCL) が必要です.

# ちなみに CMU はカーネギーメロン大学で,SB は鉄鋼銀行 (カーネギーは鉄鋼王だから ?) らしいです.CMUCL のブランチが SBCL.CMUCL よりも豊富なプラットフォーム,ネイティブスレッド,国際化などの特徴があるそうです.

C++ で GCC を書き直せば,今の C で無理やり OOP や template 相当の処理をしているようなところが全部標準 C++ 化できますし,GGC の黒魔術も smart pointer で不要になることなどが期待できます.

まぁ,個人的には,面白いとは思いますけど,労多くして実利が少ないプロジェクトだろうな,という気がします.あと,GCC の内部がわかりやすくなってしまうと,ちょっと寂しいかなという気も w あの,全体的に無理やり C で Lisp プログラミングやってるような感じが,マニアにはたまらないのです ww

なによりも,せっかく MIT AI ラボで夢破れた筋金入りの Lisper RMS が,あえて C を使って, 20 年もかけて怨念のように進めてきた苦労を全否定するのか!という(笑)

そもそも C++ コンパイラと,LISP コンパイラのどっちが多くの環境で実行可能で,よりポピュラーかと言えば,それは火を見るよりも明らかですしねぇ (仮にもし GCC の記述言語に LISP が採用されたならば,ポピュラリティが逆転し,もしかしたら RMS の積年の夢が叶うのかもしれませんが w). GCC のフロントエンドがサポートする言語に,LISP はありませんしね (GCC の構造的に,たぶん LISP のような言語の最適化にはあんまり向かない気がします.GCC で,比較的低水準な命令型言語以外のフロントエンドを作ろうとすると,仮にできたとしても,gcj みたいに,巨大なフロントエンドとランタイムが後からくっつく,不恰好でバランスが悪いものになると思います)

ちなみに、gcc は Cコンパイラの実装としてもかなり「終わって」いる。これはもとから内部の各モジュールが分離できないように わざとからみあって設計されている。つまり GPL な部分を分離して商用コードをくっつけられないようにしてあるらしい。だから構文解析や中間コード生成にフックを入れるのはものすごく大変だ。たしか RMS 自身がそのことをどっかで説明してたんだけど見つからない。

フックを入れること自体はそんなに難しくないですし,むしろ 4.x からはフロント-ミドル-バックエンドの分離が進んで簡単になってきてますけど,中間表現の完全な dump と read が不可能な構造になってるということを言いたいのでしょうね.

RMS が,バックエンドのフリーライドを防ぐため,あえてソースの直接改造が必要不可欠な構造にしてあるようです (GCC と独立して,中間表現のダンプと読み込みが可能になってしまうと,フロントエンド〜ミドルエンド部分だけを GPL フリーに作ってつなげることが可能になってしまう)

マイコミジャーナル 【レポート】 gcc 4.0来春登場 - 互換性・速度に課題も
4 gccのあの問題点は解決可能なのか?


また「完全な内部形式のTree Dumpを取りたい」という意見については、小島氏は「実はこれはRMSの方針で「完全なダンプは出さないようにすること」ということになっている」との事実を明らかにした。これは「完全なダンプを出力可能にすると、ProprietaryなBackend Pathを作られてしまう可能性がある」という理由からだと言うのだが、一方で開発者にとって完全なダンプが取れることが非常に魅力的であるという事情もあることから、事前に何らかの文書等を交わしたユーザに限り完全なダンプの出力機能を利用可能にするといったことができないか現在検討が行われている、と同氏は語った。

個人的には,誰が作ってようが,ライセンスが GPL でちゃんと全てソースが公開されてれば自由なソフトウェアだと思います.

現在 gcc を開発しているのはもはやボランティアグループなどではない。かれらは RedHat や Apple だ。こういう企業の仕事を「フリー (自由な)」ソフトウェアと呼ぶにはもう無理があるよ。

PCC (Portable C Compiler) に LLVM (Low Level Virtual Machine) に,修正 BSD ライセンスの C/C++ コンパイラが求められている背景があって,貴重なマンパワーが分散してしまってもったいない気もしますが.まぁ,これもまた FOSS って感じで良いんじゃないですかね.
マイコミジャーナル 【レポート】 GCCに匹敵するコンパイラ?! LLVM - BSDCan2008
# LLVM は,言わばコード生成と実行全体のフレームワークなので,コンパイラフレームワークの GCC と単純に比較できるようなものではないと思うので,この記事のタイトルは語弊があるなぁと思うわけですが… まぁ,それはまた別のお話.
GCCTB:0CM:2 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

ビルトイン関数をサポートし,GCC 4.3.0 に対応したバージョンをリリースしました

2008/05/09(金) 02:25:00

ほぼ全て QLeap (SATO daisuke) さんのおかげで,puts や printf などのビルトイン関数が動くようになりました.C フロントエンドから切り出してきた,ビルトイン型と関数の初期化部分 (bl.h, bl-builtins.c と Make-lang.in などの修正) が追加されてます.


bl-0.0.1-for-gcc-4.3.0.tar.bz2

GCC 4.3.0 から,それぞれのフロントエンドでビルトイン関数の初期化を行うように変更されたので,以前は何もしないで使えていた C フロントエンドのビルトインさえも,初期化しないと使えなくなりました (SEGV る). 僕一人だったら,対応はおろか,原因の追求すら困難だったと思います.僕がグズグズしている間にデバッガをフル稼働してガリガリコード書いてくださった QLeap さんと,コメント欄で助言をくださった favaritething さんに感謝感謝です.今回の件で,オープンソース開発の素晴らしさを再認識しました.非常に素晴らしい経験ができたと思います.これで,なんとか OSC 2008 の発表に間に合いそうです.

(OSC 2008 北海道で「ゆるふわ愛され GCC Hacks (仮)」 セミナーやります.みんな来てね!(笑))

gcc_hacks_osc2008_2008_05_09.png


この切り出してきた部分を流用すれば,他のフロントエンドを書くときにも,初期化が楽になると思います.

なんか謎のエラーが出る


$ ../bin/gcc

In function 'fizzbuzz':
bl1: error: type mismatch in binary expression






D.1167 = n % 101
bl1: internal compiler error: verify_gimple failed
Please submit a full bug report,
with preprocessed source if appropriate.
See for instructions.


ので,一ヶ所醜いハックがありますが,以下のような fizzbuzz.bl プログラムが動くようになりました.

この記事の続きを読む…
GCCTB:0CM:7 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

enable-checking=all, disable-bootstrap でリビルドした

2008/04/30(水) 04:05:24

GCC のビルドは,デフォルトでは 3 回コンパイルされるのですが,開発中は時間がかかってしょうがないのでウザいです.

Bootstrap stage0 : Stage1 gcc をホストシステムの gcc でビルド
Bootstrap stage1 : Stage2 gcc を Stage1 gcc でビルド
Bootstrap stage2 : Stage3 gcc を Stage2 gcc でビルド
Bootstrap stage3 : Stage2 gcc と Stage3 gcc が同一バイナリかどうかをチェック

あと,今最小限のフロントエンドを作ってるんですが,なぜか ICE が出てしまうので,原因を特定するために,全ての runtime check を有効にしてリビルドしました.--enable-checking=all は,--enable-checking=assert, fold, gc, gcac, misc, rtl, rtlflag, runtime, tree と等価です.

あと,今回はちゃんと別ディレクトリでやってみました (前回とソースツリーは同じ.一応再展開してますけど.あと,bl 以下を minimal frontend に差し替えている)

$ ../gcc-4.3.0/configure --prefix=/usr/local/build-gcc/build-bl --enable-languages=bl --enable-checking=all --disable-nls --disable-bootstrap
$ make
$ ls
Makefile config.status i686-pc-linux-gnu libdecnumber
build-i686-pc-linux-gnu fixincludes intl libiberty
config.log gcc libcpp
$ make install
$ ls
Makefile config.status include libcpp man
bin fixincludes info libdecnumber serdep.tmp
build-i686-pc-linux-gnu gcc intl libexec share
config.log i686-pc-linux-gnu lib libiberty
$ ./bin/gcc -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ../gcc-4.3.0/configure --prefix=/usr/local/build-gcc/build-bl --enable-languages=bl --enable-checking=all --disable-nls --disable-bootstrap
Thread model: posix
gcc version 4.3.0 (GCC)

参考文献 : Diego Novillo, GCC Internals., CGO 2007 Workshops and Tutorials (International Symposium on Code Generation and Optimization), March 2007 (PDF)

あと,ICE が出るのは,ちゃんと return 0 してないからじゃないか ? とかテキトーな仮説を立てて書いてみた最小フロントエンド.しかし,integer_type_node しか使ってないのに,なぜかエラーが出る…

ソースコード (bl1.c 以外は同じはず)

# 追記 ここから
@QLeap さんにデバッグしていただきました.ありがとうございます m(_ _)m

QLeap @alohakun blog にある最小のフロントエンドだと、 fold_build1 の第2引数を integer じゃなくて void_type_node にすれば、一応途中の ICE は出なくなりますね。

QLeap それでも最後に SEGV して ICE 出ますけど

QLeap 最初の問題は、 tree-cfg.c の L.4050 で出てます。 RETURN_EXPR で来た場合は VOID_TYPE じゃないと駄目らしい。

QLeap 最後のICEはtree.cのlist_length()内、p = TREE_CHAIN(p)でsegmentation fault

alohakun @QLeap おお〜,素晴らしい.ビルド通って,a.out 出ました.ありがとうございます.RETURN_EXPR の型は void ってことなんですかね

alohakun @QLeap むむむ… うちの環境だと,正常に動きました… そっちだと動かないのですか.

QLeap @alohakun そういう事でしょうね。あれ〜、そこだけでビルド通りましたか。良かった。

うちの環境だと,

tree main_ret = fold_build1(RETURN_EXPR, void_type_node, main_setret);

だけで動いてしまいました.う〜ん,だけど,公開してる方では integer_type_node で RETURN_EXPR 作ってるなぁ… 謎過ぎる.

# 追記終わり

$ mkdir test
$ cd test
$ touch null.bl
$ cat ../../gcc-4.3.0/gcc/bl/bl1.c
...

static void bl_parse_file(int debug) {
  /* function prototype : int main(); */
  tree main_type   = build_function_type(integer_type_node, NULL_TREE);
  tree main_fndecl = build_fn_decl("main", main_type);
  DECL_EXTERNAL(main_fndecl) = false;
  DECL_ARTIFICIAL(main_fndecl) = false;
  TREE_STATIC(main_fndecl) = true;
  TREE_PUBLIC(main_fndecl) = true;
  DECL_CONTEXT(main_fndecl) = NULL_TREE;
  /* null block : { } */
  tree stmts = alloc_stmt_list();
  tree  block = build_block(NULL_TREE, // variables
                            NULL_TREE, // subblocks
                            NULL_TREE, // supercontext
                            NULL_TREE);// next same level block
  DECL_INITIAL(main_fndecl) = block;
  /* int main() { }  (bind) */
  DECL_SAVED_TREE (main_fndecl) = build3(BIND_EXPR, void_type_node,
      BLOCK_VARS(block), stmts, block);
  /* create the result variable */
  tree resdecl = build_decl(RESULT_DECL, NULL_TREE, integer_type_node);
  DECL_CONTEXT(resdecl) = main_fndecl;
  DECL_RESULT(main_fndecl) = resdecl;

  /* int main() {return 0;} */
  // pascal like semantics : result := 0 (return value)
  tree main_setret = fold_build2(MODIFY_EXPR,
                                 TREE_TYPE(main_fndecl),
                                 DECL_RESULT(main_fndecl),
                                 integer_zero_node);
  fprintf(stderr, "0\n");
  TREE_SIDE_EFFECTS(main_setret) = true;
  fprintf(stderr, "1\n");
  TREE_USED(main_setret) = true;
  fprintf(stderr, "2\n");
  tree main_ret = fold_build1(RETURN_EXPR, integer_type_node, main_setret);
  fprintf(stderr, "3\n");
  append_to_statement_list(main_ret, &stmts);
  fprintf(stderr, "4\n");
  allocate_struct_function(main_fndecl, false);
  fprintf(stderr, "5\n");
    dump_function (TDI_original, main_fndecl);
  gimplify_function_tree(main_fndecl);
    //dump_function (TDI_generic, main_fndecl);
  fprintf(stderr, "6\n");
  current_function_decl = NULL_TREE;
  set_cfun (NULL);
  cgraph_node(main_fndecl);
  fprintf(stderr, "7\n");
  cgraph_finalize_function(main_fndecl, /* nested function ? */false);
  fprintf(stderr, "8\n");
  cgraph_finalize_compilation_unit();
  fprintf(stderr, "9\n");
  cgraph_optimize();
}
...

$ ../bin/gbc -fdump-tree-all null.bl
0
1
2
3
4
5
In function 'main':
bl1: error: type error in return expression
return D.19
bl1: internal compiler error: verify_gimple failed
Please submit a full bug report,
with preprocessed source if appropriate.
See for instructions.
$ cat null.bl.003t.original
main ()
{
return 0;
}


う〜ん,なぜか main 関数の返り値の型が無いな…

この記事の続きを読む…
GCCTB:0CM:0 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

最近のコメント

リンク

このブログをリンクに追加する

最近のトラックバック

人生の残り日数

日本人男性の平均寿命は 28700日.

RSSフィード

カテゴリー