Files
quartz-research-note/content/mimiumのMIRコンパイル過程を真面目に考える.md
松浦 知也 Matsuura Tomoya 857e71b45e
Some checks failed
Build / build (push) Failing after 12m59s
[obsidian] vault backup: 2025-09-25 14:38:57[
2025-09-25 14:38:57 +09:00

135 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
date: 2024-10-20 12:02
---
#mimium
ツリー形式からBasicBlockのインストラクション形式に変える
Stateのこととupvalueを両方処理しなくてはならない。ワンパスで処理できるのか
StateSize計算とUpvalue計算の両方をtraitとして切り出す方がいいのかな
## 値
$$
\begin{align}
v \; ::= & \quad R \\
| & (\lambda x:\tau.e, [\Gamma, x:e],StateStorage(p,Vec)) \quad & [Closure]\\
\end{align}
$$
$$
\begin{align}
e \; ::=& \quad x \quad x \in \mathbb{V} \quad & [value]\\
|& \quad \lambda x.e \quad & [lambda]\\
|& \quad e \; e \quad & [appglobal,stateful)]\\
|& \quad appcls \; e \; e \quad & [appclosure]\\
|& \quad fix \; x.e \quad & [fixpoint]\\
|& \quad getstate \; e \; I_n \; I_s \quad & [feed] \\
|& \quad delay \; e \; e & [delay]\\
\end{align}
$$
結局[[The w-calculus a synchronous framework for the verified modelling of digital signal processing algorithms|W計算]]のStaged Interpreterと変わらんかもな
そうすると型付けの時点でクロージャ相当の項とグローバル関数適用の項は分かれることになる?エフェクトとして考えるのが妥当なのかな
## 型
$$
\begin{align}
\tau ::=&\quad R_a \quad & a \in \mathbb{N}\\
|&\quad I_n \quad &n \in \mathbb{N} \\\
|&\quad \tau → \tau \quad \\
% |&\quad \langle \tau \rangle
\end{align}
$$
## コンパイル
評価をしながら副作用としてMIRを書き込んでいくような感じ
Valueとして、次のようなものがあり得る
```rust
struct VRegister(usize);
struct StackSlot(usize);
enum Value{
Static(usize),
Global(usize),
Function(usize),
ExternalItem(usize),
Register(VRegister),
StackSlot(StackSlot),//引数とかはこれで処理して良い
}
```
原則、Letが出てくればStackSlotに確保、そうでない一次変数はRegisterに確保でよい
LetだけどRegisterに逃がせるとか、RegisterからStackへスピルするとかはオプティマイザの範疇
基本的にはFuncProtoはValueに依存しない構造にしたい
今はmir::ValueにmirgenとBytecodeGen両方が依存しているが、Valueは本来Expr→MIR生成時に使われるだけの中間的な値であるべき
```rust
struct MIR{
name:Symbol,
static_data:Vec<StaticData>
externals:<ExternalItems>
functions:Vec<FuncProto>
}
struct Operation{
dest:Option<VRegister>,
inst:Instruction
}
struct UpIndex(usize)
struct UpIndexStorage(Vec<StackSlot>)
impl UpIndexStorage{
fn get_upv_index(&self,i:UpIndex)->Option<StackSlot>{
self.0.get(i.0)
}
}
struct FuncProto{
upindexes:UpIndexStorage,
instructions: Vec<Operation>
}
enum Instruction{
Load(StackSlot,Type)
Store{dest:StackSlot,src:Register,Type}
GetUpValue(UpIndex,Type)
//その他、プリミティブな命令はfrom Register to Register
}
```
```rust
fn eval(e:ExprNodeId,env:Env<Value>)->(Value,Type){
match e.to_expr() {
Expr::Id(name)=>{
env.lookup(name)
},
Expr::Let(name,e,body)=>{
let env = env.extend((name,eval(e,env).0));
eval(e,env)
},
Expr::App(e,args)=>{
let (f,ft) = eval(e,env);
let argvs = args.iter().map(|e| eval(e,env));
match f{
Value::Closure(fproto,names,body,env)=>{
let kvs = names.iter().zip(argvs.zip()).collect()
let env = env.extend(kvs);
eval(body,env)
}
_=>panic!()
}
}
}
}
```