123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2023 DaiLambda, Inc. <contact@dailambda.jp> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)openCostlangmoduletypeS=sigtypesizevalsize_ty:sizeTy.ttypeunop=Log2|Sqrt(* binops of [size -> size -> size] *)typebinop_size=Add|Sat_sub|Mul|Div|Max|Min(* binops of [size -> size -> bool] *)typebinop_bool=Eq|Lttype_t=|Size:Num.t->sizet|Bool:bool->boolt|Unop:unop*sizet->sizet|Binop_size:binop_size*sizet*sizet->sizet|Binop_bool:binop_bool*sizet*sizet->boolt|Shift:[`Left|`Right]*sizet*int->sizet|Free:Free_variable.t->sizet|Lam:string*'aTy.t*'bt->('a->'b)t|App:('a->'b)t*'at->'bt|Let:string*'at*'bt->'bt|If:boolt*sizet*sizet->sizet|Variable:string*'aTy.t->'atvalterm_size:'a.'at->intvaltype_of:'at->'aTy.tvalpp:Format.formatter->_t->unit(** To OCaml parsetree *)valto_expression:_t->Parsetree.expression(** Existentials *)typepackedvalpack:'at->packedvalunpack:'aTy.t->packed->'atoption(** Optimizations *)(* Charge at least 10 milli-gas. For example,
[fun size1 size2 -> size1 + size2]
=> [fun size1 size2 -> max 10 (size1 + size2)]
*)valat_least_10:'at->'at(* [let x = e1 in e2] => [e2[e1/x]] *)valsubst_let:'at->'atvaloptimize_affine:'at->'atvalcse:'at->'atend(* Need to parameterize the size if we want to make a transformer *)moduleMake(A:sigtypesizevalsize_ty:sizeTy.tend)=structincludeAtypeunop=Log2|Sqrt(* binops of [size -> size -> size] *)typebinop_size=Add|Sat_sub|Mul|Div|Max|Min(* binops of [size -> size -> bool] *)typebinop_bool=Eq|Lttype_t=|Size:Num.t->sizet|Bool:bool->boolt|Unop:unop*sizet->sizet|Binop_size:binop_size*sizet*sizet->sizet|Binop_bool:binop_bool*sizet*sizet->boolt|Shift:[`Left|`Right]*sizet*int->sizet|Free:Free_variable.t->sizet|Lam:string*'aTy.t*'bt->('a->'b)t|App:('a->'b)t*'at->'bt|Let:string*'at*'bt->'bt|If:boolt*sizet*sizet->sizet|Variable:string*'aTy.t->'attype'aast='atletrectype_of:typea.at->aTy.t=function|Size_->A.size_ty|Bool_->Ty.Bool|Unop_->A.size_ty|Shift_->A.size_ty|Binop_size_->A.size_ty|Binop_bool_->Ty.Bool|Free_->A.size_ty|Lam(_name,ty,b)->Ty.Arrow(ty,type_ofb)|Let(_v,_m,t)->type_oft|App(f,_t)->(matchtype_offwithTy.Arrow(_tf,tr)->tr)|Variable(_,ty)->ty|If(_,t,_)->type_oftletrecterm_size:typea.at->int=function|Size_->1|Bool_->1|Unop(_,t)->term_sizet+1|Binop_size(_,t1,t2)->term_sizet1+term_sizet2+1|Binop_bool(_,t1,t2)->term_sizet1+term_sizet2+1|Shift(_,t,_)->term_sizet+1|Free_->1|Lam(_,_,t)->term_sizet+1|App(t1,t2)->term_sizet1+term_sizet2+1|Let(_,t1,t2)->term_sizet1+term_sizet2+1|If(t1,t2,t3)->term_sizet1+term_sizet2+term_sizet3+1|Variable_->1moduleParsetree=structopenAst_helperletloctxt={Asttypes.txt;loc=Location.none}letloc_identx={Asttypes.txt=Longident.Lidentx;loc=Location.none}letloc_str(x:string)={Asttypes.txt=x;loc=Location.none}letidentx=Exp.ident(loc_identx)letpvarx=Pat.var(loc_strx)letsaturatedname=["S";name]letcallfargs=letf=WithExceptions.Option.get~loc:__LOC__@@Longident.unflattenfinletargs=List.map(funx->(Asttypes.Nolabel,x))argsinExp.(apply(ident(locf))args)letstring_of_fvfv=Format.asprintf"%a"Free_variable.ppfvletrecto_expression:typea.at->Parsetree.expression=function|Booltrue->Exp.construct(loc_ident"true")None|Boolfalse->Exp.construct(loc_ident"false")None|Size(Inti)->call(saturated"safe_int")[Exp.constant(Const.inti)]|Size(Floatf)->call(saturated"safe_int")[call["int_of_float"][Exp.constant@@Const.float(string_of_floatf)];]|Binop_size(Add,t1,t2)->call["+"][to_expressiont1;to_expressiont2]|Binop_size(Sat_sub,t1,t2)->call(saturated"sub")[to_expressiont1;to_expressiont2]|Binop_size(Mul,t1,t2)->call["*"][to_expressiont1;to_expressiont2]|Binop_size(Div,t1,t2)->call["/"][to_expressiont1;to_expressiont2]|Binop_size(Max,t1,t2)->call(saturated"max")[to_expressiont1;to_expressiont2]|Binop_size(Min,t1,t2)->call(saturated"min")[to_expressiont1;to_expressiont2]|Unop(Log2,t)->call["log2"][to_expressiont]|Unop(Sqrt,t)->call["sqrt"][to_expressiont]|Freename->Exp.ident(loc_ident(string_of_fvname))|Binop_bool(Lt,t1,t2)->call["<"][to_expressiont1;to_expressiont2]|Binop_bool(Eq,t1,t2)->call["="][to_expressiont1;to_expressiont2]|Shift(`Left,t,bits)->call["lsl"][to_expressiont;Exp.constant(Const.intbits)]|Shift(`Right,t,bits)->call["lsr"][to_expressiont;Exp.constant(Const.intbits)]|Lam(name,_ty,b)->letpatt=pvarnameinExp.fun_NolabelNonepatt(to_expressionb)|App(f,t)->Exp.apply(to_expressionf)[(Nolabel,to_expressiont)]|Let(name,m,b)->letvar=pvarnameinletm=to_expressionminletb=to_expressionbinExp.let_Nonrecursive[Vb.mkvarm]b|If(c,t,f)->Exp.ifthenelse(to_expressionc)(to_expressiont)(Some(to_expressionf))|Variable(name,_ty)->identnameendletto_expression=Parsetree.to_expressionletppppft=Pprintast.expressionppf@@Parsetree.to_expressiont(* Existential *)typepacked=Packed:'aTy.t*'at->packedletpackt=Packed(type_oft,t)letunpack:typea.aTy.t->packed->atoption=funty(Packed(ty',t))->matchTy.equaltyty'withNone->None|SomeRefl->Somet(* Dig into lambdas and apply [f] to the first expression of type [Ty.Size] *)letapply_to_size=letrecg:typea.(sizet->sizet)->at->at=funft->matchtwith|Lam(name,ty,t)->Lam(name,ty,gft)|Free_->ft|Unop_->ft|Shift_->ft|Size_->ft|Binop_size_->ft|If(_,_,_)|Let(_,_,_)|App_|Variable_->(matchTy.equal(type_oft)A.size_tywith|None->t|SomeRefl->ft)|Binop_bool_->t|Bool_->tingletat_least_10t=letrecf=function|Let(v,m,t)->Let(v,m,ft)|t->Binop_size(Max,Size(Int10),t)inapply_to_sizeftletsubst_lett=letrecf:typea.(string*packed)list->at->at=funenvt->matchtwith|Variable(name,ty)->(matchList.assoc~equal:String.equalnameenvwith|None->t(* The variable may be lambda-bound *)|Someentry->(matchunpacktyentrywithNone->assertfalse|Somet->t))|Let(name,m,t)->letm=fenvminf((name,packm)::env)t|Unop(op,t)->Unop(op,fenvt)|Binop_size(op,t1,t2)->Binop_size(op,fenvt1,fenvt2)|Binop_bool(op,t1,t2)->Binop_bool(op,fenvt1,fenvt2)|Shift(dir,t,n)->Shift(dir,fenvt,n)|Lam(name,ty,body)->ifList.mem_assoc~equal:String.equalnameenvthenStdlib.failwith(Printf.sprintf"Ast.subst_let: name collision: %s"name)elseLam(name,ty,fenvbody)|App(t1,t2)->App(fenvt1,fenvt2)|If(c,t,e)->If(fenvc,fenvt,fenve)|Size_|Bool_|Free_->tinf[]t(* (..(x1 op x2) .. op ..) op xn) *)letreccombine_tsidop=function|[]->id|[t]->t|t1::t2::ts->combine_tsidop(Binop_size(op,t1,t2)::ts)moduleAffine=structmoduleComponent:sig(* [n] or [expr * n]. [expr] is neither an addition nor a constant. *)typet=privateCompofsizeastoption*Num.tvalcomp:sizeastoption*Num.t->tvalpp:Format.formatter->t->unitvalmul:t->Num.t->tvalto_ast:t->sizeastend=structtypet=Compofsizeastoption*Num.tletcomp(e,n)=matchewith|None->Comp(None,n)|Somee->(match(e,n)with|Binop_size(Add,_,_),_->assertfalse|Size_,_->assertfalse|_,(Int0|Float0.0)->Comp(None,Int0)|_->Comp(Somee,n))letppppf(Comp(e,n))=matchewith|None->Num.ppppfn|Somee->Format.fprintfppf"%a * %a"ppeNum.ppn(* m * (expr * n) = expr * (m * n) *)letmul(Comp(e,n))=function|Num.Int0|Float0.0->(* 0 * (expr * n) = 0 *)comp(None,Num.Int0)|m->comp(e,Num.mulmn)letto_ast=function|Comp(None,n)->Sizen|Comp(Somet,(Int1|Float1.0))->t|Comp(Some_,(Int0|Float0.0))->Size(Int0)|Comp(Somet,size)->Binop_size(Mul,t,Sizesize)endopenComponent(* n * exp * .. * exp => n, [exp; ..; exp]
[exp]s are sorted.
*)letextract_multst=letrecextract_multst=matchtwith|Sizen->(n,[])|Binop_size(Mul,t1,t2)->letn1,mults1=extract_multst1inletn2,mults2=extract_multst2in(Num.muln1n2,mults1@mults2)|_->(Int1,[t])inletn,mults=extract_multstin(n,List.sortStdlib.comparemults)moduleT:sig(* [Σ comp_i],
- [comp_i = expr_i * n_i] do not share the same [expr]
- [comp_i]s are sorted
*)typet=privateComponent.tlistvalto_ast:t->sizeastvalof_ast:sizeast->tvalconcat:t->t->tvalcompare:t->t->[>`GT|`LE|`Unknown]end=structtypet=Component.tlistlet_ppppfcomps=letopenFormatinpp_print_list~pp_sep:(funppf()->fprintfppf"@ + ")Component.ppppfcompsletnormalizecomps=letopenListin(* We do not normalize keys for simplicity *)letkeys=letcomparek1k2=match(k1,k2)with|None,None->0|None,Some_->1|Some_,None->-1|Somet1,Somet2->Stdlib.comparet1t2insort_uniqcompare@@map(fun(Comp(k,_))->k)compsinfilter_map(funkey->letweight=fold_leftNum.add(Int0)@@map(fun(Comp(_k,v))->v)@@find_all(fun(Comp(key',_))->key=key')compsinmatchweightwith|Int0|Float0.0->None|_->Some(comp(key,weight)))keys(* m * Σ comps_i = Σ m * comps_i *)(* should keep the normalization *)letmul_scalarcompsm=matchmwith|Num.Int0|Float0.0->[]|_->List.map(funcomp->Component.mulcompm)compsletto_astcomps=combine_ts(Size(Int0))Add@@List.mapComponent.to_ast@@normalizecompsletonet=[comp(Somet,Num.Int1)]letrecof_astast:t=matchastwith|Size(Inti)->[comp(None,Inti)]|Size(Floatf)->[comp(None,Floatf)]|Binop_size(Add,t1,t2)->of_astt1@of_astt2|Binop_size(Mul,_,_)->(letm,ts=extract_multsastinmatchtswith|[]->[comp(None,m)]|[t]->letcomps=of_asttinmul_scalarcompsm|_->[comp(Some(combine_ts(Size(Int1))Mults),m)])|_->oneastletof_astast=normalize@@of_astastletcomparet1t2=ifList.for_all(fun(Comp(k1,w1))->matchList.find_map(fun(Comp(k,v))->ifk=k1thenSomevelseNone)t2with|None->false|Somew2->Num.comparew1w2<=0)t1then`LEelseifList.for_all(fun(Comp(k2,w2))->matchList.find_map(fun(Comp(k,v))->ifk=k2thenSomevelseNone)t1with|None->false|Somew1->Num.comparew1w2>=0)t2then`GTelse`Unknownletconcatt1t2=normalize(t1@t2)endincludeTend(* max (max e1 e2) e3 => [e1; e2; e3] *)letrecextract_maxest=matchtwith|Binop_size(Max,t1,t2)->letmaxes1=extract_maxest1inletmaxes2=extract_maxest2inmaxes1@maxes2|_->[t]letoptimize_affine=letrecf:typea.at->at=funt->matchtwith|Binop_size(Add,t1,t2)->lett1=ft1inlett2=ft2inAffine.(to_ast(concat(of_astt1)(of_astt2)))|Binop_size(Mul,t1,t2)->lett1=ft1inlett2=ft2inAffine.(to_ast@@of_ast@@Binop_size(Mul,t1,t2))|Binop_size(Max,_,_)->letmaxes=extract_maxestinletmaxes=List.mapfmaxesinletmaxes=List.mapAffine.of_astmaxesin(* try to simplify *)letmaxes=letrecfacc=function|[]->List.revacc|m::ms->ifList.exists(funm'->matchAffine.comparemm'with|`LE->true|`GT|`Unknown->false)(acc@ms)thenfaccmselsef(m::acc)msinf[]maxesinletmaxes=List.mapAffine.to_astmaxesincombine_ts(Size(Int0))Maxmaxes|Variable_|Size_|Free_|Bool_->t|Lam(v,ty,t)->Lam(v,ty,ft)|Unop(op,t)->Unop(op,ft)|Shift(dir,t,n)->Shift(dir,ft,n)|If(c,t,e)->If(fc,ft,fe)|Let(n,t1,t2)->Let(n,ft1,ft2)|App(t1,t2)->App(ft1,ft2)|Binop_size(Sat_sub,t1,t2)->Binop_size(Sat_sub,ft1,ft2)|Binop_size(Div,t1,t2)->Binop_size(Div,ft1,ft2)|Binop_size(Min,t1,t2)->Binop_size(Min,ft1,ft2)|Binop_bool(op,t1,t2)->Binop_bool(op,ft1,ft2)infmodulePackMap=Map.Make(structtypet=packedletcompare=Stdlib.compareend)moduleCSE=struct(* Count the sub-term occurrences for CSE *)letcountt=letadd:typea.at->intPackMap.t->intPackMap.t=funtmap->letk=packtinletn=Option.value~default:0@@PackMap.findkmapinPackMap.addk(n+1)mapinletrecf:typea.at->intPackMap.t->intPackMap.t=funtmap->matchtwith|Free_|Variable_|Size_|Bool_->map|Unop(_,t')->letmap=ft'mapinaddtmap|Shift(_,t',_)->letmap=ft'mapinaddtmap|Binop_size(_op,t1,t2)->letmap=ft1mapinletmap=ft2mapinaddtmap|Binop_bool(_op,t1,t2)->letmap=ft1mapinletmap=ft2mapinaddtmap|If(c,t1,t2)->letmap=fcmapinletmap=ft1mapinletmap=ft2mapinaddtmap|Let(_,t1,t2)->letmap=ft1mapinletmap=ft2mapinaddtmap|App(t1,t2)->letmap=ft1mapinletmap=ft2mapinaddtmap|Lam(_,_,t')->letmap=ft'mapinaddtmapinftPackMap.emptyletbuild_replace_mapt=letcount_map=counttinletcntr=ref0inPackMap.filter_map(fun_entry->function|1->None|_->(* more than once *)incrcntr;letname=Printf.sprintf"w%d"!cntrinSomename)count_map(* Replace sub-terms occur multiple times and returns the replaced variables *)letrecreplace:typea.at->stringPackMap.t->at*String.Set.t=funtmap->let(++)=String.Set.unioninmatchPackMap.find(packt)mapwith|Somename->(Variable(name,type_oft),String.Set.singletonname)|None->(matchtwith|Free_|Variable_|Size_|Bool_->(t,String.Set.empty)|Unop(op,t')->lett',s=replacet'mapin(Unop(op,t'),s)|Shift(dir,t',n)->lett',s=replacet'mapin(Shift(dir,t',n),s)|Binop_size(op,t1,t2)->lett1,s1=replacet1mapinlett2,s2=replacet2mapin(Binop_size(op,t1,t2),s1++s2)|Binop_bool(op,t1,t2)->lett1,s1=replacet1mapinlett2,s2=replacet2mapin(Binop_bool(op,t1,t2),s1++s2)|If(t1,t2,t3)->lett1,s1=replacet1mapinlett2,s2=replacet2mapinlett3,s3=replacet3mapin(If(t1,t2,t3),s1++s2++s3)|Let(v,t1,t2)->lett1,s1=replacet1mapinlett2,s2=replacet2mapin(Let(v,t1,t2),s1++s2)|App(t1,t2)->lett1,s1=replacet1mapinlett2,s2=replacet2mapin(App(t1,t2),s1++s2)|Lam(v,ty,t')->lett',s=replacet'mapin(Lam(v,ty,t'),s))(* how many times [v] appears in [t] *)letreccount_var:typea.string->at->int=funvt->matchtwith|Variable(v',_)whenv=v'->1|Variable_|Free_|Size_|Bool_->0|Unop(_,t')->count_varvt'|Shift(_,t',_)->count_varvt'|Lam(_,_,t')->count_varvt'|Binop_size(_,t1,t2)->count_varvt1+count_varvt2|Binop_bool(_,t1,t2)->count_varvt1+count_varvt2|Let(_,t1,t2)->count_varvt1+count_varvt2|App(t1,t2)->count_varvt1+count_varvt2|If(t1,t2,t3)->count_varvt1+count_varvt2+count_varvt3(* let x = e in e' => e'[e/x] when x appears only once in e' *)letexpand_one_time_lett=letrecf:typea.packedString.Map.t->at->at=funenvt->matchtwith|Variable(v,ty)->(matchString.Map.findvenvwith|Somee->(matchunpacktyewith|None->assertfalse|Somet->fenvt)|None->t)|Free_|Size_|Bool_->t|Unop(op,t')->lett'=fenvt'inUnop(op,t')|Shift(dir,t',n)->lett'=fenvt'inShift(dir,t',n)|Binop_size(op,t1,t2)->lett1=fenvt1inlett2=fenvt2inBinop_size(op,t1,t2)|Binop_bool(op,t1,t2)->lett1=fenvt1inlett2=fenvt2inBinop_bool(op,t1,t2)|If(t1,t2,t3)->lett1=fenvt1inlett2=fenvt2inlett3=fenvt3inIf(t1,t2,t3)|Let(v,t1,t2)->(lett1=fenvt1inmatchcount_varvt2with|0->fenvt2|1->letenv=String.Map.addv(packt1)envinfenvt2|_->Let(v,t1,fenvt2))|App(t1,t2)->lett1=fenvt1inlett2=fenvt2inApp(t1,t2)|Lam(v,ty,t')->lett'=fenvt'inLam(v,ty,t')infString.Map.emptytletcse:typea.at->at=funt->let_ty=type_oftinletreplace_map=build_replace_maptinletvs=List.of_seq@@PackMap.to_seqreplace_mapin(* [vs] are free of let-bindings. Sorting them by their sizes, we can
sort them in their dependencies! *)letvs=List.sort(fun(Packed(_,t1),_)(Packed(_,t2),_)->compare(term_sizet1)(term_sizet2))vsinexpand_one_time_let@@List.fold_right(fun(packed,name)acc->matchpackedwith|Packed(_ty,t)->(* avoid replace itself *)letreplace_map'=PackMap.removepackedreplace_mapinLet(name,fst@@replacetreplace_map',acc))vs(fst@@replacetreplace_map)letcset=apply_to_sizecsetendletcse=CSE.cseendmoduleAst=Make(structtypesize=Num.tletsize_ty=Ty.numend)moduleTo_ast(Ast:S):Costlang.Swithtype'arepr='aAst.tandtypesize=Ast.size=structtypesize=Ast.sizeletsize_ty=Ast.size_tytype'arepr='aAst.topenAstletfalse_=Boolfalselettrue_=Booltrueletfloatf=Size(Floatf)letinti=Size(Inti)let(+)xy=Binop_size(Add,x,y)let(*)xy=Binop_size(Mul,x,y)letsat_subxy=Binop_size(Sat_sub,x,y)let(/)xy=Binop_size(Div,x,y)letmaxxy=Binop_size(Max,x,y)letminxy=Binop_size(Min,x,y)letshift_leftxs=Shift(`Left,x,s)letshift_rightxs=Shift(`Right,x,s)letlog2x=Unop(Log2,x)letsqrtx=Unop(Sqrt,x)letfree~name=Freenameletltxy=Binop_bool(Lt,x,y)leteqxy=Binop_bool(Eq,x,y)letlam'~namety(f:'arepr->'brepr)=Lam(name,ty,f(Variable(name,ty)))letlam~name=lam'~namesize_tyletappfarg=App(f,arg)letlet_~name(typea)(m:arepr)(f:arepr->'brepr):'brepr=letvar=Variable(name,type_ofm)inLet(name,m,fvar)letif_condiftiff=If(cond,ift,iff)endmoduleTransform(F:functor(Ast:S)->sigvaltransform:'aAst.t->'aAst.tend):Costlang.Transform=functor(X:Costlang.S)->structmoduleAst=Make(structtypesize=X.sizeletsize_ty=X.size_tyend)includeTo_ast(Ast)moduleT=F(Ast)type'arepr='aAst.ttypex_repr_ex=X_repr_ex:'aTy.t*'aX.repr->x_repr_exletrecprj':typea.(string*x_repr_ex)list->arepr->aX.repr=funenvt->matchtwith|Variable(name,ty)->(matchList.assoc~equal:String.equalnameenvwith|None->assertfalse|Some(X_repr_ex(ty',xa))->(matchTy.equaltyty'with|None->assertfalse|SomeRefl->xa))|Lam(name,ty,b)->X.lam'~namety(funxa->letenv=(name,X_repr_ex(ty,xa))::envinprj'envb)|Let(name,m,t)->X.let_~name(prj'envm)(funxa->letenv=(name,X_repr_ex(Ast.type_ofm,xa))::envinprj'envt)|Size(Inti)->X.inti|Size(Floatf)->X.floatf|Booltrue->X.true_|Boolfalse->X.false_|Unop(Log2,t)->X.log2(prj'envt)|Unop(Sqrt,t)->X.sqrt(prj'envt)|Binop_size(Add,t1,t2)->X.(+)(prj'envt1)(prj'envt2)|Binop_size(Sat_sub,t1,t2)->X.sat_sub(prj'envt1)(prj'envt2)|Binop_size(Mul,t1,t2)->X.(*)(prj'envt1)(prj'envt2)|Binop_size(Div,t1,t2)->X.(/)(prj'envt1)(prj'envt2)|Binop_size(Max,t1,t2)->X.max(prj'envt1)(prj'envt2)|Binop_size(Min,t1,t2)->X.min(prj'envt1)(prj'envt2)|Binop_bool(Eq,t1,t2)->X.eq(prj'envt1)(prj'envt2)|Binop_bool(Lt,t1,t2)->X.lt(prj'envt1)(prj'envt2)|Shift(`Left,t,n)->X.shift_left(prj'envt)n|Shift(`Right,t,n)->X.shift_right(prj'envt)n|Freename->X.free~name|App(f,t)->X.app(prj'envf)(prj'envt)|If(c,t,e)->X.if_(prj'envc)(prj'envt)(prj'enve)letprjt=prj'[](T.transformt)endmoduleOptimize=Transform(functor(Ast:S)->structopenAstlettransformt=cse@@optimize_affine@@subst_lettend)moduleAt_least_10=Transform(functor(Ast:S)->structopenAstlettransform=at_least_10end)