OpeLa 進捗報告 at 第23回自作OSもくもく会
- 5. 進捗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する命令
- 6. 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;
…
};
アセンブリ命令出力用の仮想クラス
- 7. 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";
}
- 12. テストを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");
}
テストケースを呼び出し、集計する
テストケースの実行結果を確認する
- 13. テストケース紹介(一部)
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; }
- 17. 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はビルド時の
ログ形式を指定
- 18. 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を使おう