Repository | Url |
---|---|
YouTube | https://bit.ly/3XbqPSQ |
chibicc-cil | https://github.com/kekyo/chibicc-cil (まだ非公開) |
chibias-cil | https://github.com/kekyo/chibias-cil |
というか、後からチャレンジしても良いかもしれないけど、マイナーなのでやらなくても良いんじゃないかという理由。
Add -static option
- まあ、ILRepackしてください。
Add -fpic and -fPIC options
- そもそもpic概念が無いので。
- しかし、オリジナルのテストコードに、so内からシンボルの参照(
bar
)を行っていて、これが実現できない。逆方向の参照が出来るの知らなかった。 - 対応するのはnetmoduleだけど、cecilでターゲットアセンブリをロードすることなく参照する方法がわからないので、かなり無理感ある...
- ラベルをポインタに出来るGNU拡張
[GNU] Treat labels-as-values as compile-time constant
[GNU] Support labels-as-values
- 頑張れば実現できるとは思うが(真面目にポインタ値を解釈せず、ラベルをインデックスに変換してcase jumpすればいい)
Add long double
decimal
に対応させるのはアリかもしれない。多分そんなに難しくはない。- ステージ2以降はlibcにstrtoulのようなdecimal対応関数を用意すればいいが、ステージ1はそもそもgccなので、その辺りを矛盾なく通せるようにする必要がある。
- VLAの絡み
Do not define __STDC_NO_VLA__
Support sizeof(typename) where typename is a VLA
Add pointer arithmetic for VLA
Add sizeof() for VLA
- VLAは非常に厳しい。表向きにはallocaの構文サポートと言う事になるけど、CLRがスタックマシンで動的に確保されるスペースも評価スタックに積むことになり、評価スタックをスクラッチバッファとして使うコードを生成するchibiccは、スタックバランスが崩れてクラッシュしてしまう(なので、alloca使用時もスタックが底にある事をチェックしている)
- スクラッチバッファとして使う箇所を全部テンポラリローカル変数に格納するようにすれば対応は可能だが...
Add -fcommon and -fno-common flags
- このオプションの背景: https://qiita.com/yasuhirokimura/items/d5337d73a016502b9d54
- CLRの場合は、もちろん完全に区別されてしまうので、意図的に見つかった最初のシンボルを問答無用で使うようになっている。挙動としては
-fcommon
に近い。 - 上の記事を読む感じだと、シンボル再定義をエラーにしたほうがよさそうではあるけど、chibiccのテストが全面的に重複を許しているので、テスト全部に手を入れる必要があり...
- グローバル変数とローカル変数に対するアライメントの指定
- 必要性
解決済み: 80669fb0377
- Objに
kind
を持たせて、引数とローカル変数を区別可能にする。 gen_adder()
でldloca
しているところを、このタイプを見て切り替える。- プロローグコードのコピーコードを削除する。
- ほか、ローカル変数インデックスの整合性とか確認する。
解決済み: b1a1b72ecc
- 値型配列を導入して解決。
解説: https://www.youtube.com/watch?v=s0Se886xllU
- 上のトピックに絡む話。
- 動画コメント欄参照。
fn->params
とfn->locals
を分けて管理する?- 分けて管理すれば、関数プロローグコードのemit時に、余計なコードを生成しなくても良くなる。
- 分けた場合、パラメータを参照するときは
ldloca
ではなくldarga
を使う必要がある。
解決済み: 405141080ed
MaxStackSize
の問題を発見するに至ったバグ。- CIL instruction stream上には、実行されないCILコードが存在したとしても、それが評価スタックの静的実行フロー解析結果に影響を与えてはならない。
pop
,br LABEL
みたいなコードが出てしまう。pop
が評価スタックを消費するので、不正な計算をしてしまう。- ステートメントとして評価する箇所がおかしい?
解決済み: 27e509038426cb
- ポインタサイズを4バイトと仮定している。
sizeof
opcodeを使って実行時に計算する必要があるが、chibicc内で計算してしまっている。Type.size
がintの直値になっているのを、Node*
にして、計算するコードを出力するように変更すればいけそう?sizeof
出来るノード(ND_SIZEOF?)が必要? 3e55cafef でやってそう?- 79f5de21eb706ea "Add constant expression" で追加される
eval
関数のように、再帰的にノードを探索することで、事前に直値の計算ができる(reducer)。 結果をそのままgen_expr()
にかければ、直値ならND_NUMで直値が、そうでなければ式を実行するOpCode群が出力される。
解決済み: MaxStackSize
をchibiccないしchibias内部で計算しない。
- cecilで
MaxStackSize
を指定しても無視されて、cecil内部で計算された値が出力されてしまう。 - PR投げた: jbevain/cecil#892
- ディスカッションの結果、
MaxStackSize
は常時必ず静的解析によって決定できる(cecilの内部で)事がわかった。 - 実行時に評価スタックの最大値が変化するような、以下のようなコードをCILとして作ることはできるが、CLRがこれを実行できることをEMCA仕様上は担保しない(静的解析で決定できないため)。
int32 foo(int32 count)
{
.locals ([0] int32 i)
ldarg.0 ; i = count
stloc.0
L1:
ldc.i4.1 ; [increase ev stack]
ldloc.0 ; i--
ldc.i4.1
sub
stloc.0
ldloc.0 ; if (i != 0) goto L1
ldc.i4.0
ceq
brfalse L1
; (snip: decrease ev stack by count)
ret
}
- chibias内でこれを検出してwarningを出しても良いかもしれない(削除した実行フロー解析をいじれば出来そう)
- chibiccの実装のおかげで、それほど大変でもない気がしてきた(自分で展開するのではなく、
.tailcall
を使用) - せっかく
.tailcall
出来るので... C#でもできないし。 - やるならオプションで有効化(
.tailcall
されるとデバッガがスタックフレームをたどれなくなるのでデバッグしやすさに影響がある)
- codegenの
to_typename()
で型名を毎回生成している。 - ポインタを
Type
にキャッシュできる。 - 対応済み。
- 何度もreduceした場合に高速化される。
- いや、
is_reduced
フラグを用意すればいい... - 対応済み。
解決済み: b1a1b72ecc
- 値型配列を導入して解決。
解説: https://www.youtube.com/watch?v=s0Se886xllU
- 効率重視とchibiccの実装に寄せるため、ローカル変数をポインタ (
int*
) として配置するようにした。 - 当初実装(ビデオ中で"V1"と呼んでいた)では
int[]
としていたけど、ヒープアロケーションを避けたかった。 - しかし、
int*
だと、デバッガで配列の中身を普通に参照できないので、それはそれで辛そう。 - やるならオプションで有効化するのが良いんじゃないかと思った。
- 注意深く実装しないと、そのまま翻訳するとネストした配列が文字通りのjaggedになってしまう。ネストした配列こそ多次元配列型を使うと良いかもしれない。
- これを見ると、多次元配列の要素へのポインタを直接ネストしたC配列として扱っているように見えるので、メモリ上の配置についてはn*mみたいに普通に配置されることを前提として良さそうではある https://learn.microsoft.com/en-us/dotnet/framework/interop/marshalling-different-types-of-arrays#declaring-prototypes
ILGenerator
の事を失念していて、ラベルのfixup処理を全部自前で書いてしまった。ちゃんと動いているからいいけど、switch
OpCodeを実装するときにめんどくさそう...ILGenerator
を使ってラベルを管理するようにしたほうが良いと思う。InlineSwitch対応するときにも、ILGenerator
ベースになっていたほうが実装しやすそう。
勘違いっぽい? cecilのILProcessor
には、DefineLabel()
などは存在しない。
extern __declspec(dllimport("foo.so")) void bar(int a, char* b);
みたいなのを定義できると良いのでは?
- 内部では、P/Invokeのエントリを生成して、実際にDLL呼び出しに解決させる。
- めんどくさいので、C#のラッパーライブラリを作るので十分だと判断すれば、ボツにする。
- 方式3パターン案:
__declspec(dllimport("foo.so"))
のようにライブラリ名書かせる: もっとも実現が容易で、マルチプラットフォーム対応の支障はない。元の属性指定には存在しない構文なのがネック。__declspec(dllimport)
や、書かなくても認識できる: コマンドラインに指定されたライブラリファイルを読み取り、自力でシンボル名の存在チェックを行う必要がある。現状、マルチプラットフォームで使えるポータブルなシンボル名解決方法がなさそう。linux系はnm
を使えるが、もしかしたら出力フォーマットがプラットフォームで違うかもしれない。又はlibelf
を使う。Macやそのほかの対応方法がわからんので、nm
に丸投げは移植のしやすさを考えると現実的かもしれない。Windowsはimagehlp.dll
を使う?
- ELFとPEにしか対応できないが、.NET Coreとmonoが動く対象を考えると、まあこれでも良いかとは思う(Macが問題)。
- ライブラリ名書かせることが出来て、かつ、書かなくてもライブラリを指定すれば自動的に認識できる、と言うのが、互換性においても柔軟性においてもベターだと思う。
- 資料: libelf: https://atakua.org/old-wp/wp-content/uploads/2015/03/libelf-by-example-20100112.pdf
- 資料: imagehlp: https://stackoverflow.com/questions/4606628/viewing-export-table-on-an-unmanaged-dll-in-c-sharp
- 資料: imagehlp: https://stackoverflow.com/questions/4353116/listing-the-exported-functions-of-a-dll
Macはちょっと調べたけど、端的に言って何言ってるかよくわからん感じなので、興味あると手を挙げた人が居れば任せようと思う(.soは.oってことですかね、それにしてはdlopen
でロードできるとも言われてて、本当に歴史的事情なのかどうかもわからん...)
JetBrainsから近しいものが出てるけど、シンボルのトラバースは出来ない?
- https://stackoverflow.com/questions/2892097/parsing-plain-win32-pe-file-exe-dll-in-net
- 自力でやるなら: https://qiita.com/cha1aza/items/f64dc4351517a2477ef1
- https://qiita.com/7of9/items/ee080b1c99fe269aaee6
- https://github.com/xoofx/LibObjectFile
- https://zenn.dev/drumato/books/afc3e00a4c7f1d
- https://sugawarayusuke.hatenablog.com/entry/2017/04/09/213133
__declspec
で出来ない事もないけど、結局chibildの方にも手を入れる必要はある。それに-lfoo
とかやってlibfoo.so
が参照されて欲しいよね感ある。
chibicc側からは関数シンボル(コールサイト含む)が提供されれば、ネイティブライブラリにシンボルが存在するかどうかを確認し、発見した場合はコールサイトからDllImport
を構築できるはず。
- chibiccは
call
に常にコールサイトを付けるようにする。chibild側は必須ではないが、コールサイトが無い場合はネイティブライブラリとリンクできない(無視するか?エラーにするか?)
解決済み: a0ff71d42c780
chibiasは、0.20.0で実装済み。.enumeratiuon
ディレクティブをサポートして、出力できるようにする。- chibiccは、 c82c8335aa55 の後で、メタデータを出力するように実装する。
解決済み: 7b6121a9f7160
- 現状では、構造体メンバーにのみ適用し、グローバル・ローカル変数への指定は無視かまたは警告を表示という方向に逃げようと思う。
- グローバル・ローカル変数に指定したいという欲求は、
_mm_load_si128()
とかやりたい人ですよね? そもintrin.h
はCLRではできない。
- グローバル・ローカル変数に指定したいという欲求は、
- chibiasでalignment指定できるようにしようと思ったが、再計算が面倒なので、chibicc側でパディングメンバーを生成する方針に変更。
以下、検証:
#include <stdio.h>
#include <stdint.h>
struct x1 { // 8
char a; // 0
int b; // 4
};
struct x2 { // 16
_Alignas(4) char a; // 0
_Alignas(8) int b; // 8
};
struct x3 { // 16
struct x1 a; // 0
struct x1 b; // 8
};
struct x4 { // 24
struct x1 a; // 0
struct x2 b; // 8
};
struct x5 { // 24
_Alignas(8) struct x1 a; // 0
_Alignas(8) struct x2 b; // 8
};
struct x6 { // 8
_Alignas(8) char a; // 0
_Alignas(4) int b; // 4
};
struct x7 { // 28
struct x6 a; // 0
struct x2 b; // 12
};
struct x8 { // 8 / 12
char *a; // 0
int b; // 4 / 8
};
struct x9 { // 16
int a; // 0
_Alignas(8) char b; // 8
int c; // 12
};
#define PTR(p) ((uint8_t*)(p))
void main()
{
struct x1 x1[2];
struct x2 x2[2];
struct x3 x3[2];
struct x4 x4[2];
struct x5 x5[2];
struct x6 x6[2];
struct x7 x7[2];
struct x8 x8[2];
struct x9 x9[2];
printf("x1=%ld, %ld\n", PTR(&x1[1].a) - PTR(&x1[0].a), sizeof(x1[0]));
printf("x2=%ld, %ld\n", PTR(&x2[1].a) - PTR(&x2[0].a), sizeof(x2[0]));
printf("x3=%ld, %ld\n", PTR(&x3[1].a) - PTR(&x3[0].a), sizeof(x3[0]));
printf("x4=%ld, %ld\n", PTR(&x4[1].a) - PTR(&x4[0].a), sizeof(x4[0]));
printf("x5=%ld, %ld\n", PTR(&x5[1].a) - PTR(&x5[0].a), sizeof(x5[0]));
printf("x6=%ld, %ld\n", PTR(&x6[1].a) - PTR(&x6[0].a), sizeof(x6[0]));
printf("x7=%ld, %ld\n", PTR(&x7[1].a) - PTR(&x7[0].a), sizeof(x7[0]));
printf("x8=%ld, %ld\n", PTR(&x8[1].a) - PTR(&x8[0].a), sizeof(x8[0]));
printf("x9=%ld, %ld\n", PTR(&x9[1].a) - PTR(&x9[0].a), sizeof(x9[0]));
}
解決済み
- C言語の用語で、Flexible arrayという。
struct foo {
int a;
int b[]; // <-- System.Int32_len0として生成しているが...
}
専用の実装を用意する(対応済み: 0.28.0: 901c94124e7b8eb0)- 名前は、
System.Int32_flex
のようになる。
- 名前は、
意図的に(対応済み: 0.28.0: 901c94124e7b8eb0)IOBE
を発生させない現在のインデクサ実装は、内部的にもポインタ計算でアクセスしているので、挙動としては望ましい(? 少なくともC言語同様にオーバーランアクセスを意図的に起こせる)
(対応済み: 0.28.0: 901c94124e7b8eb0 、publicなLengthを実装しない)System.Int32_len0.Length
がint.MaxValueを返すとか- IList.Countの実装では、
InvalidOpEx
かNotImplEx
を投げるか。
- IList.Countの実装では、
System.Int32_flex
は明示的にSize=0
をつけたほうが良いかも。- メンバフィールドは定義されていないが、こういう構造体の
sizeof
オプコードが1になったような記憶がある... - やっぱり駄目だった。サイズが0にはならない。構造体にflexible arrayが含まれる場合は、メンバそのものではなくアクセサを公開するようにする(chibias)
- chibiasの変更は結構面倒なので、いったん諦める。Flexible arrayを含む構造体を使うには、構造体へのポインタという形でしか使用しないと思われるので、その実体型のサイズが問題になることはほとんどない&ましてやC#などでそのシビアな型のインスタンスを直接取り扱うというシチュエーションが想像できない(Flexible array内の要素を参照することはありうるが、それは構造体へのポインタ経由
p->fa[123]
しかありえない)
- メンバフィールドは定義されていないが、こういう構造体の
- シンプルなのが良いと思ったけど、関数シグネチャをサポートした関係で
TypeParser
に統合したほうが良いと思った。 call System.Console.WriteLine string
が、call System.String.WriteLine void(string)
と書かなければならなくなる。op_Implicit
やop_Explicit
に対応できる(戻り値型を明示するため)- メソッド検索部分は戻り値型を検証していないので、対応する必要がある。
- 割と最近?のCLRで、戻り値型の反変に対応したとか見た気がする。CLRの問題だったかRoslynの問題だったかは忘れた。
TypeParser
で対応済み。戻り値型の反変には未対応。但しオーバーロード選択ではop_Implicit
とop_Explicit
以外で戻り値の型を見てないため、コード自体は問題なく出力される(反変を満たす型でかつCLRが対応していれば動くと思われる)。
解決済み: d0a78fd0fa418
gen_expr(Node *, bool discard)
みたいにフラグをつけるgen_addr(Type *, bool discard)
みたいにフラグをつけて、true
だったらldind
しない。true
で呼び出す側はpopしないvoid
result function(EVSに積まれてなければ、戻り値型がvoid
なら何も考慮する必要はない?)
- 自動生成されたCILソースコードをアセンブルしたい(生成したソースコードファイルは維持されないので失われるから)
.file
または.location
で指定させるか、ほかのディレクティブを追加する。_start()
の扱いと統合させる。.hidden
を追加した。
Marshal.StringToHGlobalAnsi()
を使っているが、これは環境依存でUTF-8にならない疑いMarshal.StringToCoTaskMemUTF8()
というのが増えているが、.NET 6以上なので却下_start()
でちまちま実装するというのもあるが、いっそlibcを作るときにヘルパーメソッドを配置したほうが良いかも(そうするとlibc必須になるのでそれはそれでシンプルさは失われるので、どうするか)- エントリポイントは
_entry()
みたいな名前にして、直ぐに_start()
を呼ぶ。_start()
はlibcに配置しておくが、自分で作ってもいい(chibiasで参照時にlibcより先に見つかれば問題ない)、と言う事にするか。 - 対応済み。常に
Encoding.UTF8
を使って真面目に実装した。デメリットとしてargv
を要求すると、corlibへの参照が発生する(toolchainのドキュメントに書いた)
int add_all(int n, ...) {
va_list ap;
va_start(ap, n);
int sum = 0;
for (int i = 0; i < n; i++)
sum += va_arg(ap, int);
return sum;
}
の、sum = 0
で、ND_MEMZERO
と思われる初期化ノードが挿入される。
.locals (
[0] int32*,
[1] int32*,
[2] int32 i,
[3] int32 sum,
[4] valuetype [mscorlib]System.ArgIterator ap
)
IL_000b: ldloca 3 ; ND_MEMOZERO?
IL_000f: initobj [mscorlib]System.Int32 ; ND_MEMOZERO?
IL_0015: ldloca 3
IL_0019: ldc.i4 0
IL_001e: stind.i4
直後に0で初期値を代入しているので無駄。なんでこうなっているのか調べる必要がある。
- 元々こういう動作かも?又は移植時のバグか?
ND_MEMZERO
についてのコメントがあった気がする。0クリア初期化が要求されている(確か初期化式がある場合、という条件だったような気も)
今更... しかも後方互換性なし...
- 参考: https://ufcpp.net/study/csharp/datatype/inline-array/
- 多分対応しない。
- 今のchibildはFixed length arrayをstructで生成するけど、長さだけのフィールドを生成してしまう。OldCLRとCoreCLRはフィールド数に影響がなさそう(?)だけど、monoだと目に見えてロードが遅くなる(30000とかのオーダーで目撃)。もし、
array<T>
のT型にポインタ型かintptr
が含まれていなければ、StructLayout(Size=n)
でサイズ指定することで、条件付きながら多量のフィールド数を削減できると思う。
CallingConvention.Varargに対応するのはWindowsだけというクソ仕様...
おまけに、netstandard2.0のアセンブリでTypedReference
を使うと、CoreCLRがクラッシュするなど挙動がおかしい。
monoはすべてにおいて正しく動作する。
上記のような状況なので、ArgIterator
を使うのをやめて、__va_list
クラスをlibcに用意して、これらのヘルパーを使うように変更してみたが、まだしっくり来ていない。また、chibildでPInvoke自動対応をやりたいので、このクラスを廃止して、Vararg前提のコードを出力するようにした方が良いのではないかと考えている。
- 呼び出し先が.NETメソッド(関数を含む)である場合は、
params object[]
相当の引数を受ける前提にする。 C#と親和性は高い。デメリット:- 呼び出し元は、コールサイトの指定が必須となる(可変引数部分を特定するため)。また、配列を生成するためのtrampoline又はshrinkerをchibild内で生成して、それを呼び出す必要がある。
- chibiccは
arglist
OpCodeとArgIterator
を使って普通に書かせる。chibildでこれらのOpCodeやメンバを検出して、params object[]
配列から値を取り出すコードに変換する(要難度検証)。
- 呼び出し先がVarargやPInvokeメソッドである場合は、sentinel parameterを設定して、Varargに普通に対応させる。
- chibiccが出力したコードはそのまま使用できる。
- 現在の所monoかWindows CoreCLRでしか動かない。
params object[]
に対応させるために勝手にコードを弄るのはかなりキモイが、PInvokeの場合に特別に対応させるよりも難易度が低そう(arglist
やArgIterator
などの目立つ目印があるので)。
最後の制約は、これを読んでエンハンスが出来そうなら考える: https://github.com/jeremyVignelles/va-list-interop-demo
まだラフなアイデア。AnyCPUのメンバオフセットをキャッシュ($disp
)するようにしたけど、それでも目に見えて32,64前提コンパイルした方が速くなる。
また、AnyCPUだと一部のマクロが定数にならないので、ソースコード互換性に影響がある。そこで:
chibicc -m32 -mproxy
chibicc -m64 -mproxy
みたいにして、32と64で別々のコンパイルを行う。
その後、chibicc -mproxy
みたいにすると、AnyCPUのプロキシコードが出力出来て、これは実行時の32/64を判定して前述のどちらかのアセンブリに処理を自動的にバイパスする、みたいな感じ。
- 関数はバイパスできそう。
- グローバル変数とか型が怪しい。無理かも。
TypeForwardedTo
を動的にやれるような方法があると良いが... CoreCLRにはもしかしたらくちがあるかもしれないけど、OldCLRやmonoで出来ないならやらない。- 無理な場合は制約としたとしても、あると嬉しい機能かどうかは検討が必要。
おそすぎる。
- 簡易的に測ってみたところ、やはりアセンブリ参照のロードに時間がかかる(
mscorlib
とかSystem.Private.CoreLib
が大きい)。 mscorlib
で、ロードにかかる時間と、ハッシュ値計算にかかる時間を計測した: https://gist.github.com/kekyo/004e6970d9e442c96b672838a9e18a9d
ですよねぇという感じ。Cecil deferred: 00:00:00.0525979, 00:00:00.0993047, Total=00:00:00.1519026 Cecil immediate: 00:00:00.4901391, 00:00:00.0162472, Total=00:00:00.5063863 MD5: 00:00:00.0129031 SHA1: 00:00:00.0177283 SHA256: 00:00:00.0388692
- 現状、
Immediate
モードでロードしているけど、これはCecilがマルチスレッドアクセス多分不可で、lazy loadされると競合条件にひっかかるんじゃないかと思っているため。Deferred
モードにするだけで半分以下に出来るけど、そうするとアクセスするたびにロックが必要になってしまう。ロックによる効率低下より、ロック忘れが怖い。 - ハッシュ値計算の速度を測ったのは、パブリックシンボルをキャッシュ(例えば
~/.chibicc-toolchain/
配下に)することで高速化できるかどうかを考えたため。- 衝突が起きるかどうかの心配だけなので、MD5でも良いかもしれない。なんならボディにファイルへのパスを含めて、想定パスと一致しているかどうかを検査すればいい。
Deferred
と比べても10倍違うので、期待できる。AssemblyLoadedFragment
を書き直さなければならない...
- tagと
typedef
によるシンボル名をCILに反映させる具体的な方法- tagがないパターン
- typedefされる場合: 初回の
typedef
名を受け取る? 安定的か? - 匿名型のインスタンス化: 完全にユニーク名でおk?
- typedefされる場合: 初回の
- タグ名にはスコープがあるので、それをどうするか
- スコープをCILでも実現する(
C.text.type.foo
,C.text.func1.type.foo
? ちょっと無理があるかも) - ユニーク名。ユニークと言ってもpointer valueではdeterministicを確保できないのと、コンパイル単位が違っても予測可能でなければならない。但し、関数スコープ内であれば予測可能ユニーク名でなくても問題ない(外から見えないから)。CILメタデータ的には区別が必要。
- スコープのネストにユニークインデックスをつける。インクリメンタル:(
foo
,foo1
,foo2
,foo3
, ...), ツリー:(foo
,foo1
,foo1_1
,foo1_2
,foo2_1
, ...)
- スコープをCILでも実現する(
- 全く同じ定義の共通化
- tagがないなら積極的にやりたい
- tagがある場合は人間が区別したいと考えていると仮定して、同じでも別の定義にする?(C言語的に代入互換性があるかどうか?
- tagがないパターン
- MSBuild
- .cprojとかやりたい。
- むしろ、.csprojや.fsprojにプラグインできる方法もあったほうが良い(今のMSBuildのアンチテーゼとして)
chibicc.build
とは別に必要か。又は今のchibicc.build
を別の名前に変更して導入か。- 一から対応させる方法としては、MSBuildSdkExtrasが参考になるかも。
- 「PackageReference を何ひとつ書かなくても NETStandard.Library を勝手にダウンロードしてくるのは、手軽にコードが書けるという点ではいいかもしれないけれど、やはり無駄なパッケージ参照があるというのは許せないものなので、消していきましょう。」 https://azyobuzin.hatenablog.com/entry/2017/03/23/032246
mastodonで呟こうかとも思ったけど、ここに落としておく。
そういえば、stage2出来た後でchibiccの速度を比べると、圧倒的ですよgccベースのchibiccは... 多分10倍ぐらい違う。
というか、chibiccは最適化されていないコードを吐くとはいえ、CLRは実行時に何もしてないのかというぐらい遅い。
理由は調べてない(やるとしたら終わってから)けど、色々資料を見るにつけ、C#に最適化し過ぎではとは思ってる。
これを頑張ってC#が吐くコードぽく近づけたとしても、gccには遠く及ばないだろうなという推測も。
2~3倍ぐらいにまでは寄せれるかもしれないけど。