SlideShare a Scribd company logo
1 of 35
Download to read offline
Type-level C Compiler
(THIS MAY INDICATE
OUT OF MEMORY)
eliza0x (現代魔術研究会)
こんにちはこんにちは!
● 大阪工業大学 コンピュータ科学科(も
う無くなったんでしたね) B4
● プログラミング言語が好きです
● TOEIC300点プレイヤーです
○ 最近勉強をはじめたので、とりあえず中学
英文法レベルなら分かるようになりました
● 卒研では画像から特徴量を抽出する
回路を設計しています
● 今日は超ニッチなネタなのでウケるか
ちょっと不安です
Type-level C Compiler
(THIS MAY INDICATE
OUT OF MEMORY)
再掲
プログラミングの計算能力
● あるプログラミング言語Aとあるプログラミング言語Bの計算能力が同じであること
を示したい時、どうすればいいと思いますか?
● AでBを実装できると、A >= Bであることがわかる。
● BでAを実装できると、A <= Bであることがわかる。
● そのどちらも可能である場合、A == Bであることがわかる。
チューリング完全
● チューリング・マシン
○ 無限の長さのテープとその上を行き来す
るヘッドを持っている仮想的な機械で、
ヘッドがテープから読み取ったデータと今
持っている状態に応じてヘッドを動作させ
る
○ アラン・チューリングが考案
● C言語など、一般的なプログラミング
言語はチューリングマシンと同じ計算
能力を持っていることが証明されてい
ます。
引用:
https://en.wikipedia.org/wiki/Turing_machine#/medi
a/File:Model_of_a_Turing_machine.jpg
Esolangs
● Esolang: 難解プログラミング言語
● 理論の美しさを第一に考えて設計されていたり
● 難解になるように設定されていたり
Brainfuck
チューリングマシンみたいな難解言語
1. > ポインタをインクリメントする。ポインタをptrとすると、C言語の「ptr++;」に相当する。
2. < ポインタをデクリメントする。C言語の「ptr--;」に相当。
3. + ポインタが指す値をインクリメントする。C言語の「(*ptr)++;」に相当。
4. - ポインタが指す値をデクリメントする。C言語の「(*ptr)--;」に相当。
5. . ポインタが指す値を出力に書き出す。C言語の「putchar(*ptr);」に相当。
6. , 入力から1バイト読み込んで、ポインタが指す先に代入する。C言語の「*ptr=getchar();」に相当。
7. [ ポインタが指す値が0なら、対応する ] の直後にジャンプする。C言語の「while(*ptr){」に相当。
8. ] ポインタが指す値が0でないなら、対応する[ (の直後)にジャンプする。C言語の「}」に相当
wikipedia brainfuckより引用: https://ja.wikipedia.org/wiki/Brainfuck
+++++++++[>++++++++>+++++++++++>+++>+<<<<-]>.>++.+++++++..+++.
>+++++.<<+++++++++++++++.>.+++.------.--------.>+.>+.
Unlambda
K
(SII(S(K(S(S(K(SII(S(S(KS)(S(K(S(KS)))(S(K(S(S(KS)(SS(S(S(KS)K))(KK)))))
(S(S(KS)(S(KK)(S(KS)(S(S(KS)(S(KK)(S(KS)(S(S(KS)(S(KK)(SII)))
(K(SI(KK)))))))(K(S(K(S(S(KS)(S(K(SI))(S(KK)(S(K(S(S(KS)K)(S(S(KS)K)I)
(S(SII)I(S(S(KS)K)I)(S(S(KS)K)))))(SI(K(KI)))))))))(S(KK)K)))))))(K(S(KK)
(S(SI(K(S(S(S(S(SSK(SI(K(KI))))(K(S(S(KS)K)I(S(S(KS)K)(S(S(KS)K)I))
(S(K(S(SI(K(KI)))))K)(KK))))(KK))(S(S(KS)(S(K(SI))(S(KK)(S(K(S(S(KS)K)))
(SI(KK))))))(K(K(KI)))))(S(S(KS)(S(K(SI))(SS(SI)(KK))))(S(KK)
(S(K(S(S(KS)K)))(SI(K(KI)))))))))(K(K(KI))))))))))(K(KI)))))(SI(KK)))))
(S(K(S(K(S(K(S(SI(K(S(K(S(S(KS)K)I))(S(SII)I(S(S(KS)K)I)))))))K))))
(S(S(KS)(S(KK)(SII)))(K(SI(K(KI)))))))(SII(S(K(S(S(KS)(S(K(S(S(SI(KK))
(KI))))(SS(S(S(KS)(S(KK)(S(KS)(S(K(SI))K)))))(KK))))))(S(S(KS)
(S(K(S(KS)))(S(K(S(KK)))(S(S(KS)(S(KK)(SII)))(K(S(S(KS)K)))))))(K(S(S(KS)
(S(K(S(S(SI(KK))(KI))))(S(KK)(S(K(SII(S(K(S(S(KS)(S(K(S(K(S(S(KS)(S(KK)
(S(KS)(S(K(SI))K))))(KK)))))(S(S(KS)(S(KK)(S(K(SI(KK)))(SI(KK)))))
(K(SI(KK))))))))(S(S(KS)(S(K(S(KS)))(S(K(S(KK)))(S(S(KS)(S(KK)(SII)))
(K(SI(K(KI))))))))(K(K(SI(K(KI)))))))))(S(K(SII))(S(K(S(K(SI(K(KI))))))
(S(S(KS)(S(KK)(SI(K(S(K(S(SI(K(KI)))))K)))))(K(S(K(S(SI(KK))))
(S(KK)(SII)))))))))))(K(SI(K(KI))))))))(S(S(KS)K)I)
(SII(S(K(S(K(S(SI(K(KI)))))K))(SII)))))
● SKI計算ですね
Piet
● 画像が実行ファイルになる難解言語
● 色の変化量で次の移動先と
実行する命令を決める
うっかりチューリング完全になったものたち
● Rule 110のセル・オートマトン
● Magic: The Gathering (Arxivに論文があるみたいです
● HTML5 + CSS
● スーパーマリオメーカー
● Minecraft
○ レッドストーン回路は計算機を作るのに夢中になったことがあるのは僕だけじゃないはず :)
● 繰り返しますが、これらは一般的なプログラミング言語と同じだけの計算能力を
持っているということです
○ (理論上は、実際はメモリや盤面、カード枚数などの制約がある )
今日示すもの
Haskellの型システムは
チューリング完全である
今日作るもの
Haskellの型システム上で
Cで書かれた
C Compilerを動かす
作るもの
1. 型レベルCPU
2. C Compiler
型レベルCPU
型システム
● 雑に言うと1 + ‘A’をするとエラーを出してくれるやつです
型システム
● 『正しく型付けされた項はおかしくならない』ことを示すためのものです。
○ 単純型付きラムダ計算は、型がつくならば必ず有限ステップで停止することを証明することが出来
る
○ ⇔ループが書けない
○ それは不便すぎるのでできるだけ安全なまま制約を緩めたシステムが開発されてきた (再帰型付
け、部分型付け等)
● 今日は型システムを使っておかしなことをします
type family: 型族
● Haskell(GHC)にはtype familyといって、平たく言うと型レベルの関数を定義するた
めの機能があります
● 関数として見ると
○ 高階関数は使えない
○ なんかいろいろ演算のための機能が足りない (プリミティブを組み合わせて表現した )
○ 変数が定義できない
○ 型システムが無い(一応kindと言って型の型みたいなのはある )
はじめにCPUを定義します
● 型レベルでしか存在しないCPUです(つまり幽霊型です。)
○ 入力用のバッファと出力用のバッファ (自然数のリスト)
○ メモリ(二分木, 平衡を実装していないので実質リスト )
○ プログラムカウンタ(pc)
○ レジスタ(a-d, sp, bp)
● これに操作を加えるいくつかの演算を定義します
● レジスタ長は24bitです
命令
● 高階関数が無いのでなんかすごいつらい実装になってます
コンパイル時型レベルCPU
● CPUの完成です
● 簡単に見えるが、そもそも型システムはプログラムを書くためのものではないため
デバッグがしんどかった
● printfすらない
C Compiler
つらい
● こんな一発ネタのためにCコンパイラをつくるのはめんどくさすぎる
コンパイラ基盤
● コンパイラは以下の2つで構成される
○ フロントエンド(ソースコードを解釈する)
○ バックエンド(解釈したデータから目標物を生成する)
● フロントエンドとバックエンドの間はIR(中間表現)を使ってやり取りする
● x86, arm向けのCコンパイラを作りたい場合フロントエンドは使い回せる
● 有名なバックエンドにLLVMが存在する(clang等に使われている)
● ただ、今回の目的にLLVMはリッチすぎる(中間表現が複雑)
ELVM
● LLVMインスパイアのプロジェクト、LLVMより圧倒的にシンプル
● Esoteric Language Virtual Machineの略(難解言語用VM)
● 8ccというコンパクトなCコンパイラを改造して出来ている
● ELVMを使うとCのプログラムを比較的簡単に別の言語に変換できる
○ 8cc: C source code -> EIR(ELVMの中間表現)
○ elc: EIR -> target(目的のプログラム、今回は Haskell)
● BrainfuckやBefunge、Pietなど向けのバックエンドが存在する。
ELVM IR
● 2operandのシンプルな命令セット
○ シンプルと言う割には多いような ……(ちょっとめんどくさかった )
● レジスタはA, B, C, D, SP, BP
● 算術: Add, Sub
● 比較: Eq, Ne, Lt, Le, Gt, Ge
● ジャンプ: Jmp, Jeq, Jne, Jlt, Jle, Jgt, Jge
● コピー: Mov
● メモリアクセス: Load, Store
● 入出力: putc, getc
ひたすら変換するだけ
● ELVM対応を見据えてCPUを設計したのでや
るだけ
● ELVMはすごいシンプルなインタフェースを
持っているので、場合分けをするだけ(ありが
たい)
実行例
FizzBuzz: コンパイル
● 1から100までの数値でFizz Buzzするプログラムを作成
● 8ccでC source→EIRに変換(ELVMに付属)
● elcでEIR→Haskellの型レベル命令列に変換(今回作成)
FizzBuzz
1
2
Fizz
4
Buzz
Fizz
7
8
Buzz
Fizz
Fizz Buzz: 実行
● 型レベルCPUで実行
THIS MAY INDICATE
OUT OF MEMORY
突然のOOM Killer
● なにがダメだったか
● Fizz Buzz実行に20G積んであるメモリがすべて食い尽くされた
● 一応7までの数値でFizz Buzzは動いた
● ELVMの出力するコードは最適化等が一切されていないため、かなり効率が悪い
○ そのうえ可読性が地獄、めちゃめちゃつらい
結論
● ELVMのtype level haskell backendでCコンパイラもコンパイル出来た
● つまり理論上はHaskellの型システムの上でCコンパイラが動く
● 現実的には無限にメモリが無いとしんどい
○ 1から8までのFizz Buzzで20G必要だった
○ 現状20Gのメモリだと7000命令ぐらいでメモリを食いつぶす
● 気が向けばチューニングしてみます(もしかしたらメモリを大幅に節約できるかも)
● GHC(Haskellのコンパイラ)見に行かないとダメかな……?
追記: FizzBuzz
AWSでメモリ256Gのマシン借りたら1から20までは動いた(計算に18分かかります)
追記: 改良策
● GCが無いのが悪いのでメモリが開放されるタイミングを考える
● →コンパイル終了時のみ
● type-level cpuはCPU以外で状態を持たない
● →ある程度計算するとCPUの状態をダンプして、CPUだけ途中からの状態ではじ
めからコンパイルすると良いのでは?
● →プログラムから生成されたプログラムがプログラムを生成する事態に

More Related Content

Similar to Compile Time Type Level C Compiler (this may indicate out of memory)

Define and expansion of cpp macro
Define and expansion of cpp macroDefine and expansion of cpp macro
Define and expansion of cpp macrodigitalghost
 
cbt (Cranberries Build Tool)
cbt (Cranberries Build Tool)cbt (Cranberries Build Tool)
cbt (Cranberries Build Tool)Wada Yuki
 
C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜
C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜
C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜UnityTechnologiesJapan002
 
Neural Network Console delta_tokyo_#3
Neural Network Console delta_tokyo_#3Neural Network Console delta_tokyo_#3
Neural Network Console delta_tokyo_#3AkiraYasukawa1
 

Similar to Compile Time Type Level C Compiler (this may indicate out of memory) (7)

Define and expansion of cpp macro
Define and expansion of cpp macroDefine and expansion of cpp macro
Define and expansion of cpp macro
 
計算機理論入門02
計算機理論入門02計算機理論入門02
計算機理論入門02
 
cbt (Cranberries Build Tool)
cbt (Cranberries Build Tool)cbt (Cranberries Build Tool)
cbt (Cranberries Build Tool)
 
C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜
C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜
C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜
 
C言語の課題を(エクストリームに)解こう #1
C言語の課題を(エクストリームに)解こう #1C言語の課題を(エクストリームに)解こう #1
C言語の課題を(エクストリームに)解こう #1
 
お盆明け勉強会
お盆明け勉強会お盆明け勉強会
お盆明け勉強会
 
Neural Network Console delta_tokyo_#3
Neural Network Console delta_tokyo_#3Neural Network Console delta_tokyo_#3
Neural Network Console delta_tokyo_#3
 

Compile Time Type Level C Compiler (this may indicate out of memory)