3.3 KiB
3.3 KiB
date
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 & [app(global,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の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として、次のようなものがあり得る
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生成時に使われるだけの中間的な値であるべき
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
}
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!()
}
}
}
}