SlideShare a Scribd company logo
1 of 21
OpeLaの進捗
2020年12月30日
第23回自作OSもくもく会
OpeLaプロジェクトとは
OpeLa: Operating and Language processing system
OSと言語処理系を全部自作するプロジェクト
OS
アセンブラ
コンパイラ
リンカ
ライブラリ
特徴:完全なセルフホスト
セルフホストとは(コンパイラ編)
自分自身をコンパイルすること
GCCやClangはそうなっている
GCCをビルドするのに他のコンパイラの助けは
不要
自作言語およびOSでこれをやりたい!
自作コンパイラ
ソースコード
第1世代
自作コンパイラ
入力
第2世代
自作コンパイラ
コンパイル
OpeLaの進捗
現在、コンパイラopelacを作成中
OpeLa言語仕様の策定&コンパイラ実装
進捗1:AArch64対応
進捗2:テスト自身をOpeLa言語で実装
進捗1:AArch64対応
Mac mini (M1, 2020)を手に入れ、AArch64対応を進めた
つい先日、今実装してある部分すべてがAArch64に対応した
lewing@isc.tamu.edu Larry Ewing and The GIMP
https://www.apple.com/jp/mac/m1/
void Push64(std::ostream& os, uint64_t v) override {
os << " push " << v << 'n';
}
void Push64(std::ostream& os, uint64_t v) override {
os << " mov x8, " << v << 'n';
os << " str x8, [sp, #-16]!n";
}
x86-64で整数をスタックにpushする命令
AArch64で整数をスタックにpushする命令
AArch64対応のやり方
アセンブリ命令を出力する部分を仮想クラスに抽出
各アーキ用のクラスを継承して実装
class Asm {
public:
enum Register {
kRegL,
kRegR,
kRegNum,
};
virtual void Push64(std::ostream& os, uint64_t v) = 0;
virtual void Push64(std::ostream& os, Register reg) = 0;
virtual void Pop64(std::ostream& os, Register reg) = 0;
virtual void Add64(std::ostream& os, Register lhs, Register rhs) = 0;
virtual void Sub64(std::ostream& os, Register lhs, Register rhs) = 0;
…
};
アセンブリ命令出力用の仮想クラス
Asmクラスを利用して命令を出力
Asm* asmgen;
void GenerateAsm(ostream& os, Node* node,
string_view label_break, string_view label_cont,
bool lval = false) {
switch (node->kind) {
case Node::kInt:
asmgen->Push64(os, node->value.i);
return;
ASTを受け取ってアセンブリを出力する関数
void Push64(std::ostream& os, uint64_t v) override {
os << " push " << v << 'n';
}
void Push64(std::ostream& os, uint64_t v) override {
os << " mov x8, " << v << 'n';
os << " str x8, [sp, #-16]!n";
}
AArch64に対応して分かったこと
下手に抽象化するより、実際に複数アーキに対応する段になって
抽象化する方がうまく行く
余計な抽象化を挟まず、シンプルに保てる
必要な抽象化をもれなく導入できる
AArch64には面白い命令がある
意外と複雑なアドレッシングモードがある
• x86-64の「base+scale*index」に相当するアドレッシングモードがある
• ldr x8, [x9, x10, lsl #3] は「x8←x9+(x10<<3)」
プレインデックス、ポストインデックス
str x8, [sp, #-16]!
ldr x8, [sp], #16
プレインデックス
LDR(メモリ→レジスタ)
STR(レジスタ→メモリ)
で使える
アドレス指定レジスタを事
前に変化させる
X1にSPを指定すれば
Push/Popが実現できる
https://developer.arm.com/architectures/learn-the-architecture/aarch64-
instruction-set-architecture/loads-and-stores-addressing
AArch64全般に対応したわけではない
あくまでM1 Mac(Mach-O形式)のみの対応
同じAArch64でもRaspberry Piには未対応
コンパイラ・トリプルでいうところの<arch>のみの対応
将来的には、少なくともAArch64+ELFに対応させたい
OpeLaの開発はLinux(ELFの世界)が主戦場だから
https://clang.llvm.org/docs/CrossCompilation.html
進捗2:テスト自身をOpeLa言語で実装
今まではシェルスクリプトで
テストを書いていた
各テストケース毎に
opelacでコンパイル
→ccでリンク
→バイナリを実行
を繰り返しており、遅かった
テストをOpeLa言語で実装
テスト全部入りのコードを1度
だけopelacでコンパイル
めちゃくちゃ高速化!
test_exit 42 'func main() { 42; }'
test_exit 11 'func main() { 1+23 - 13; }'
test_exit 2 'func main() { 12/2 - 2 * (3 - 1); }'
test_exit 5 'func main() { -3 + (+8); }'
func testIntConstant() { 42; }
func testAddSub() { 1+23 - 13; }
func testMulDiv() { 12/2 - 2 * (3 - 1); }
func testUnaryOp() { -3 + (+8); }
テストをOpeLa言語で書く
テストケースを関数として実装
関数を呼び出し、結果を確認
https://github.com/uchan-nos/opela/blob/master/compiler/test_run.opl
#define TEST_INT(want, got) testInt(want, got, #got)
var (passed int; failed int;)
func main() {
TEST_INT(42, testIntConstant());
TEST_INT(11, testAddSub());
…
TEST_INT(4 , testUserType());
print_int64(passed);
print_string(" passed, ");
print_int64(failed);
print_string(" failedn");
return failed > 0;
}
func testInt(want, got int, gots *byte) {
if want == got {
print_string("[ OK ]: ");
passed += 1;
} else {
print_string("[FAILED]: ");
failed += 1;
}
print_string(gots);
print_string(" -> ");
print_int64(got);
if want != got {
print_string(", want ");
print_int64(want);
}
print_string("n");
}
テストケースを呼び出し、集計する
テストケースの実行結果を確認する
テストケース紹介(一部)
func testIntConstant() { 42; }
func testAddSub() { 1+23 - 13; }
func testMulDiv() { 12/2 - 2 * (3 - 1); }
func testUnaryOp() { -3 + (+8); }
func testRelOp() { 3 < 1; }
func testRelOp2() { 2*3 >= 13/2; }
func testEqOp() { 2>2 == 4<=3; }
func testBlankBlock() { }
func testCompoundBlock() { 42; 3; }
func testDefVar() { foo:=5; bar:=3; foo*bar; }
func testReturn() { return 3; 42; }
func testIf() { 1; if 42 > 10 { 2; } }
func testIfVar() { cond := 10 < 1; 1; if cond { 2; } }
func testAssign() { foo := 3; foo = 4; foo * 2; }
func testAssign2() { foo:=5; bar:=7; foo=(bar=1)=42; foo-4; }
func testAssign3() { foo:=5; bar:=7; foo=bar=42; }
func testFor() { i:=0; s:=0; for i <= 10 { s=s+i; i=i+1; } s; }
func testAssign4() { a:=5; a=b:=3; a*b; }
func testFor2() { s:=0; for i:=0; i<=10; i=i+1 { s=s+i; } }
func testElse() { if 0 { 3; } else { 4; } }
func testElseIf() { if 0 { 3; } else if 1 { 5; } else { 4; } }
func testSimpleBlock() { 42; {} }
func testNextedFor() { s:=0; for i:=1;i<3;i=i+1{ for j:=1;j<3;j=j+1{ s=s+i*j; } } s; }
テストをOpeLaで書いて分かったこと
Cプリプロセッサが便利
特に、引数を文字列化する機能
#define TEST_INT(want, got) testInt(want, got, #got)
気づかないバグをあぶりだせた
-1+5が260になるバグ
• シェルスクリプトではテスト可能な値が0~255なので気づかなかった
• プロセスのexit codeによる制約
ローカル変数とグローバル変数の名前衝突
• グローバル変数と同じ名前のローカル変数を定義できない
意外とOpeLaでテストが書ける!
付録:VSCodeでopelacをデバッグしたい
本格的なデバッグ作業はIDEでやりたい
GDBのコマンド操作より変数等が確認しやすいから
VSCodeでC++のプログラムをデバッグする方法を模索した
Clang + gdb + Ubuntu 18.04
lldbはVSCodeでの使用に対応してないらしい…
2つのJSONファイルの設定が重要
tasks.json: プログラムのビルド手順を設定する
launch.json: プロセスの起動手順を設定する
後ほど紹介
VSCodeでopelacを
デバッグする様子
tasks.json: プログラムのビルド手順を設定する
{
"tasks": [
{
"type": "shell",
"label": "C/C++: build opelac",
"command": "make",
"args": [
"CXX=clang++"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [
"$gcc"
],
…
}
],
"version": "2.0.0"
}
type=cppbuild, shell
Cppbuild: Makefileを使わず、
command=clang++として直接
コンパイルする
Shell: シェルコマンドなんでも使
える?(未調査)
labelはlaunch.jsonから参照す
る名前
problemMatcherはビルド時の
ログ形式を指定
launch.json: プロセスの起動手順を設定する
{
"version": "0.2.0",
"configurations": [
{
"name": "opelacのビルドとデバッグ",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/opelac",
"args": ["<${workspaceFolder}/hgoe.opl"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": […],
"preLaunchTask": "C/C++: build opelac",
"miDebuggerPath": "/usr/bin/gdb"
}
]
}
programは起動対象
標準入力にファイルを渡す
にはargsに"<file"
preLaunchTaskにビルドタ
スクを指定
miDebuggerPath
MI=Machine Interface
lldbはMIに対応してないぽい
のでgdbを使おう
まとめ
OpeLaプロジェクトの概要
AArch64対応
テストのOpeLa化
VSCodeでのデバッグ
自作言語をセルフホストする道のり
第1世代
自作コンパイラ
opelac.cpp
clang++
入力
第1世代
自作コンパイラ
コンパイル
第2世代
自作コンパイラ
opelac.opl
書き直し
コンパイル
入力
第2世代
自作コンパイラ
コンパイル
第3世代
自作コンパイラ
入力
ここまでくれば
ぐるぐる回せる
(はず)
OpeLaで目指す「完全セルフホスト」
自作OSの上で動く自作言語処理系で
自作OSと自作言語処理系をビルドすること
自作OS
自作言語処理系
自作OS
ソースコード
自作言語処理系
ソースコード
Linux
GCC,binutils
LinuxとGCCの
ソースコード
Linuxでいえば

More Related Content

What's hot

316 Ch
316 Ch316 Ch
316 Ch
anjaan
 
NECビッグローブ/ビジネス事業部 グループマネージャー 山本氏
NECビッグローブ/ビジネス事業部 グループマネージャー 山本氏NECビッグローブ/ビジネス事業部 グループマネージャー 山本氏
NECビッグローブ/ビジネス事業部 グループマネージャー 山本氏
loftwork
 
090518_unix-ensembl
090518_unix-ensembl090518_unix-ensembl
090518_unix-ensembl
ocha_kaneko
 
20090219 Vvm Chi Final
20090219 Vvm Chi Final20090219 Vvm Chi Final
20090219 Vvm Chi Final
尹思哲
 

What's hot (20)

Top Ten SE Concepts V11.1 Jp
Top Ten SE Concepts V11.1 JpTop Ten SE Concepts V11.1 Jp
Top Ten SE Concepts V11.1 Jp
 
Intalio Be Workshop (Japanese)
Intalio Be Workshop (Japanese)Intalio Be Workshop (Japanese)
Intalio Be Workshop (Japanese)
 
20世紀Ruby
20世紀Ruby20世紀Ruby
20世紀Ruby
 
洋書(英語情報源)に見るDXの定義
洋書(英語情報源)に見るDXの定義洋書(英語情報源)に見るDXの定義
洋書(英語情報源)に見るDXの定義
 
A lecture on e-book at Tokyo University of Science 20141008
A lecture on e-book at Tokyo University of Science 20141008 A lecture on e-book at Tokyo University of Science 20141008
A lecture on e-book at Tokyo University of Science 20141008
 
An untold story of the Mangamura controversy 2018
An untold story of the Mangamura controversy 2018An untold story of the Mangamura controversy 2018
An untold story of the Mangamura controversy 2018
 
Programming言語Lua紹介(Internet版)
Programming言語Lua紹介(Internet版)Programming言語Lua紹介(Internet版)
Programming言語Lua紹介(Internet版)
 
6 3google
6 3google6 3google
6 3google
 
Mashup and new paradigm - マッシュアップ技術とインターネットの新しい潮流
Mashup and new paradigm - マッシュアップ技術とインターネットの新しい潮流Mashup and new paradigm - マッシュアップ技術とインターネットの新しい潮流
Mashup and new paradigm - マッシュアップ技術とインターネットの新しい潮流
 
316 Ch
316 Ch316 Ch
316 Ch
 
Rsgt2021 exploratory testing
Rsgt2021 exploratory testingRsgt2021 exploratory testing
Rsgt2021 exploratory testing
 
About OSGeo.JP
About OSGeo.JPAbout OSGeo.JP
About OSGeo.JP
 
インフラエンジニアになろう!
インフラエンジニアになろう!インフラエンジニアになろう!
インフラエンジニアになろう!
 
NECビッグローブ/ビジネス事業部 グループマネージャー 山本氏
NECビッグローブ/ビジネス事業部 グループマネージャー 山本氏NECビッグローブ/ビジネス事業部 グループマネージャー 山本氏
NECビッグローブ/ビジネス事業部 グループマネージャー 山本氏
 
35010558 1
35010558 135010558 1
35010558 1
 
Let's get into coLinux!
Let's get into coLinux!Let's get into coLinux!
Let's get into coLinux!
 
Ext Ncs 20081029
Ext Ncs 20081029Ext Ncs 20081029
Ext Ncs 20081029
 
ブランド、プロフィット、コスト、デザインを追及するコンテンツ管理とは(Oracle OpenWorld Tokyo 2009)
ブランド、プロフィット、コスト、デザインを追及するコンテンツ管理とは(Oracle OpenWorld Tokyo 2009)ブランド、プロフィット、コスト、デザインを追及するコンテンツ管理とは(Oracle OpenWorld Tokyo 2009)
ブランド、プロフィット、コスト、デザインを追及するコンテンツ管理とは(Oracle OpenWorld Tokyo 2009)
 
090518_unix-ensembl
090518_unix-ensembl090518_unix-ensembl
090518_unix-ensembl
 
20090219 Vvm Chi Final
20090219 Vvm Chi Final20090219 Vvm Chi Final
20090219 Vvm Chi Final
 

More from uchan_nos

More from uchan_nos (20)

MikanOSと自作CPUをUSBで接続する
MikanOSと自作CPUをUSBで接続するMikanOSと自作CPUをUSBで接続する
MikanOSと自作CPUをUSBで接続する
 
OSを手作りするという趣味と仕事
OSを手作りするという趣味と仕事OSを手作りするという趣味と仕事
OSを手作りするという趣味と仕事
 
小型安価なFPGAボードの紹介と任意波形発生器
小型安価なFPGAボードの紹介と任意波形発生器小型安価なFPGAボードの紹介と任意波形発生器
小型安価なFPGAボードの紹介と任意波形発生器
 
トランジスタ回路:エミッタ接地増幅回路
トランジスタ回路:エミッタ接地増幅回路トランジスタ回路:エミッタ接地増幅回路
トランジスタ回路:エミッタ接地増幅回路
 
OpeLa: セルフホストなOSと言語処理系を作るプロジェクト
OpeLa: セルフホストなOSと言語処理系を作るプロジェクトOpeLa: セルフホストなOSと言語処理系を作るプロジェクト
OpeLa: セルフホストなOSと言語処理系を作るプロジェクト
 
自作言語でお絵描き
自作言語でお絵描き自作言語でお絵描き
自作言語でお絵描き
 
サイボウズ・ラボへ転籍して1年を振り返る
サイボウズ・ラボへ転籍して1年を振り返るサイボウズ・ラボへ転籍して1年を振り返る
サイボウズ・ラボへ転籍して1年を振り返る
 
USB3.0ドライバ開発の道
USB3.0ドライバ開発の道USB3.0ドライバ開発の道
USB3.0ドライバ開発の道
 
Security Nextcamp remote mob programming
Security Nextcamp remote mob programmingSecurity Nextcamp remote mob programming
Security Nextcamp remote mob programming
 
Langsmith OpeLa handmade self-hosted OS and LPS
Langsmith OpeLa handmade self-hosted OS and LPSLangsmith OpeLa handmade self-hosted OS and LPS
Langsmith OpeLa handmade self-hosted OS and LPS
 
OpeLa セルフホストなOSと言語処理系の自作
OpeLa セルフホストなOSと言語処理系の自作OpeLa セルフホストなOSと言語処理系の自作
OpeLa セルフホストなOSと言語処理系の自作
 
自動でバグを見つける!プログラム解析と動的バイナリ計装
自動でバグを見つける!プログラム解析と動的バイナリ計装自動でバグを見つける!プログラム解析と動的バイナリ計装
自動でバグを見つける!プログラム解析と動的バイナリ計装
 
1を書いても0が読める!?隠れた重要命令INVLPG
1を書いても0が読める!?隠れた重要命令INVLPG1を書いても0が読める!?隠れた重要命令INVLPG
1を書いても0が読める!?隠れた重要命令INVLPG
 
レガシーフリーOSに必要な要素技術 legacy free os
レガシーフリーOSに必要な要素技術 legacy free osレガシーフリーOSに必要な要素技術 legacy free os
レガシーフリーOSに必要な要素技術 legacy free os
 
Building libc++ for toy OS
Building libc++ for toy OSBuilding libc++ for toy OS
Building libc++ for toy OS
 
プランクトンサミットの歴史2019
プランクトンサミットの歴史2019プランクトンサミットの歴史2019
プランクトンサミットの歴史2019
 
Introduction of security camp 2019
Introduction of security camp 2019Introduction of security camp 2019
Introduction of security camp 2019
 
30分で分かる!OSの作り方 ver.2
30分で分かる!OSの作り方 ver.230分で分かる!OSの作り方 ver.2
30分で分かる!OSの作り方 ver.2
 
Timers
TimersTimers
Timers
 
USB3 host driver program structure
USB3 host driver program structureUSB3 host driver program structure
USB3 host driver program structure
 

OpeLa 進捗報告 at 第23回自作OSもくもく会