--- 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|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} $$ ## コンパイル Valueとして、次のようなものがあり得る ```rust struct VRegister(usize);//Vregisterは無限に使用できてサイズ可変 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 externals: functions:Vec } struct Operation{ dest:Option, inst:Instruction } struct UpIndex(FnId,usize) struct UpIndexStorage(Vec) impl UpIndexStorage{ fn get_upv_index(&self,i:UpIndex)->Option{ self.0.get(i.0) } } struct BlockId(usize) struct BasicBlock{ label:Symbol, entry_v:Vec op:Vec } struct BlockChunk(Vec) impl BlockChunk{ /*newtype pattern*/ } struct FuncProto{ name: Symbol, upindexes: UpIndexStorage, blocks: BlockChunk, state_tree: Vec //StateTreeは実際のデータを保持しない meta_labels:BTreeMap //print用メタデータ } enum Instruction{ Load(StackSlot,Type) Store{dest:StackSlot,src:Register,Type}, GetUpValue(UpIndex,Type), JmpIf{cond:Register,then:BlockId,else_:BlockId,merge:BlockId}, ShiftStatePos(isize)//ツリーの子インデックスに対するカーソル移動オフセット GetState(Type) //その他、プリミティブな命令はfrom Register to Register } ``` 評価をしながら副作用としてMIRを書き込んでいくような感じ ```rust fn eval(e:ExprNodeId,env:Env<(Value,Type)>)->(Value,Type){ match e.to_expr() { Expr::Id(name)=>{ match env.lookup(name){ (Value::Register(r),t)=>(r,t) (Value::StackSlot(s),t)=>push_inst(Instruction::Load(s,t)) } }, 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!() } } Expr::Feed(id,body)=>{ } } } ```