123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-2025 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file LICENSE). *)(* *)(**************************************************************************)moduleLog=Tracelog.Make(structletcategory="Types.TypedC"end)moduleInt_option=Datatype_sig.Option(Datatype_sig.Int)moduleString_option=Datatype_sig.Option(Datatype_sig.String)moduleIn_bits=Units.In_bitsmoduleIn_bytes=Units.In_bytesmoduleSymbolMap=Datatype_sig.StringMap(** String to type map (parameter to expression) *)typevalue_symbol=stringtypevalue=Symofvalue_symbol(* We treat arrays length specially, at least for now. *)typearray_length=Fixed_lengthofZ.t|Variable_lengthofvalue_symbolletpp_valuefmt=letopenFormatinfunctionSyms->fprintffmt"\"%s\""sletpp_array_lengthfmt=letopenFormatinfunction|Fixed_lengthx->Z.pp_printfmtx|Variable_lengths->fprintffmt"\"%s\""smodulePred=structtypeunop=ExtractofIn_bits.t*In_bits.t(** start index, length *)letpp_unopoppp_exprfmtexpr=matchopwith|Extract(idx,len)->Format.fprintffmt"%a{%d, %d}"pp_exprexpr(idx:>int)((idx:>int)+(len:>int)-1)typebinop=|Add|Sub|Mul|Div|And|Or|Mod|ConcatofIn_bits.t*In_bits.t(** Size 1, size 2. First argument is the most significant *)letpp_binopfmtop=Format.pp_print_stringfmt@@matchopwith|Add->"+"|Sub->"-"|Mul->"*"|Div->"/"|And->"&"|Or->"|"|Mod->"%"|Concat(size1,size2)->Format.sprintf"::<%d,%d>"(size1:>int)(size2:>int)typeexpr=|ConstofZ.t|Valofvalue|Self|Unopofunop*expr|Binopofbinop*expr*exprtypecmpop=|Equal|NotEqual|ULt|SLt|ULeq|SLeq|UGeq|SGeq|UGt|SGtletpp_cmpopfmtop=Format.pp_print_stringfmt@@matchopwith|Equal->"="|NotEqual->"!="|ULt->"<u"|SLt->"<s"|ULeq->"<=u"|SLeq->"<=s"|UGeq->">=u"|SGeq->">=s"|UGt->">u"|SGt->">s"typemutval={id:int;mutablevalue:bool}(** Predicate on a structure field or array element, which is supposed to be
true at all times. *)typet=|True|Cmpofcmpop*expr*expr|Andoft*t|Mutvalofmutval*tletrecis_true=function|True|Mutval({value=false},_)->true|Mutval(_,p)->is_truep|_->falselettrue_=Trueletevaluate_mutval{value}p=matchvaluewithfalse->True|true->p(**initialize a mutval wich will make the associated value true*)letinit_mutvalt=letcounter=letx=ref0infun()->incrx;!xinMutval({id=counter();value=true},t)letequaltu=comparetu=0letrecpp_exprfmt=letopenFormatinfunction|Constx->Z.pp_printfmtx|Valvalue->pp_valuefmtvalue|Self->pp_print_stringfmt"self"|Unop(op,e)->fprintffmt"@[<hov 2>%a@]"(pp_unopoppp_expr)e|Binop(op,e1,e2)->fprintffmt"@[<hov 2>(%a@ %a@ %a)@]"pp_expre1pp_binopoppp_expre2letrecppfmt=letopenFormatinfunction|True->pp_print_stringfmt"true"|Cmp(cop,e1,e2)->fprintffmt"@[<hov 2>(%a@ %a@ %a)@]"pp_expre1pp_cmpopcoppp_expre2|And(p1,p2)->fprintffmt"@[<hov 2>%a@ &&@ %a@]"ppp1ppp2|Mutval(mutval,p)->ppfmt(evaluate_mutvalmutvalp)letarray_length_to_expr=function|Fixed_lengthz->Constz|Variable_lengths->Val(Syms)let_lift_unop:unop->Z.t->Z.t=function|Extract(idx,len)->funx->Z.extractx(idx:>int)(len:>int)let_lift_binop:binop->Z.t->Z.t->Z.t=function|Add->Z.add|Sub->Z.sub|Mul->Z.mul|Div->Z.div|And->Z.logand|Or->Z.logor|Concat(_,size2)->funxy->Z.logor(Z.shift_leftx(size2:>int))y|Mod->Z.remlet_lift_cmpop:cmpop->Z.t->Z.t->bool=function|Equal->Z.equal|NotEqual->funab->not(Z.equalab)|ULt->Z.lt|ULeq->Z.leq|UGeq->Z.geq|UGt->Z.gt|SLt->funxy->Int32.compare(Z.to_int32x)(Z.to_int32y)<0|SLeq->funxy->Int32.compare(Z.to_int32x)(Z.to_int32y)<=0|SGeq->funxy->Int32.compare(Z.to_int32x)(Z.to_int32y)>=0|SGt->funxy->Int32.compare(Z.to_int32x)(Z.to_int32y)>0letconjunctionpred1pred2=match(pred1,pred2)with|_whenpred1=pred2->pred1|_whenis_truepred1->pred2|_whenis_truepred2->pred1|_->And(pred1,pred2)letrecsubstitutes_exprexprenv=matchexprwith|Val(Syma)whenSymbolMap.memaenv->SymbolMap.findaenv(* | Val _ | Self -> pe *)|Unop(op,expr)->Unop(op,substitutes_exprexprenv)|Binop(op,expr1,expr2)->Binop(op,substitutes_exprexpr1env,substitutes_exprexpr2env)|_->exprletrecsubstitutespredenv=matchpredwith|True->pred|Cmp(op,e1,e2)->Cmp(op,substitutes_expre1env,substitutes_expre2env)|And(pred1,pred2)->And(substitutespred1env,substitutespred2env)|Mutval(mut,p)->Mutval(mut,substitutespenv)(*if mut.value then substitutes p env else pred*)endtypebasic=In_bytes.t*string(** Byte size and name. *)typestructure={st_byte_size:In_bytes.t;st_members:(In_bytes.t*string*typ)list;(** Offset, field name, type, and predicate on type. *)}andunion={un_byte_size:In_bytes.toption;(* Size of the union *)un_types:(string*typ)list;(* typename, and type of the field *)}anddescr=|Void(* TODO: REmove, and have flexible array member instead. *)|Baseofbasic|Structureofstructure|StructureFAMof{structure:typ;array:typ}|Ptrofpointer(** Pointed type and index of pointed element in array. For non-array
pointed types, the index should be [ConstIdx 0]. *)|Arrayoftyp*array_length(** Element type and number of elements (if statically known). *)|Functionoffuntyp(** Return type and parameter types *)|Applicationofname(*∃ bound_var : bound_typ, body*)|Existentialof{bound_var:string;bound_typ:typ;body:typ}|Unionofunion|Weakoftypandconstr_name=|ConstrNameofstring|ConstrNameFuncofstring|ConstrNameUnionofstring|ConstrNameStructofstring|ConstrNameEnumofstring|ConstrNameArrayofconstr_name(* Arity 1. Printed as name[a]* instead of name[](a)* *)(* Maybe:ConstrNameStar *)(** TODO: Should be pointing to a name only. *)andpointer={pointed:typ}andname={constr:constr;args:Pred.exprlist}andconstr={id:int;name:constr_name;arity:int}andconstr_def=typ*stringlist(* Function from a list of arguments to a type. *)andfuntyp={ret:typ;args:typlist;pure:bool}andtyp={mutabledescr:descr;mutablepred:Pred.t}typefundef={funtyp:typ;inline:bool}exceptionUndefined_type_constructorofstringmoduleStringHash=Hashtbl.Make(structincludeStringlethash=Hashtbl.hashend)letrecpp_constr_namefmt=function|ConstrNamestr->Format.fprintffmt"%s"str|ConstrNameFuncstr->Format.fprintffmt"function %s"str|ConstrNameUnionstr->Format.fprintffmt"union %s"str|ConstrNameStructstr->Format.fprintffmt"struct %s"str|ConstrNameEnumstr->Format.fprintffmt"enum %s"str|ConstrNameArraycn->Format.fprintffmt"%a[]"pp_constr_namecn(***************************************************************************************)(***************************************************************************************)(*Below are utilies manipulating the ctypes storing, which is done in an imperative way*)(***************************************************************************************)(***************************************************************************************)moduleConstr=structtypet=constrletcount=ref0lettbl=Hashtbl.create17letmakenamearity=matchHashtbl.findtblnamewith|exceptionNot_found->incrcount;letres={id=!count;name;arity}inHashtbl.replacetblnameres;res|xwhenx.arity=arity->x|x->Log.fatal(funp->p"Two uses of the same name %a with different arities (%d and %d)"pp_constr_namenamex.arityarity)lethashx=x.idletequal=(==)letcompareab=Int.comparea.idb.idletppfmtx=pp_constr_namefmtx.nameletto_stringx=Format.asprintf"%a"ppxendmoduleConstrHash=Hashtbl.Make(Constr)typectype_spec={constr_map:constr_defConstrHash.t;function_map:(string,fundef)Hashtbl.t;global_map:(string,typ)Hashtbl.t;}letctype_spec={constr_map=ConstrHash.create17;function_map=Hashtbl.create17;global_map=Hashtbl.create17;}letadd_constr_definitionconstrdef=letconstr_map=ctype_spec.constr_mapinifConstrHash.memconstr_mapconstrthenletres=ConstrHash.findconstr_mapconstrinifres=defthen()elseLog.fatal(funp->p"There is already a definition for %a"Constr.ppconstr)elseConstrHash.addconstr_mapconstrdefletconstr_of_nameconstr=ConstrHash.find_optctype_spec.constr_mapconstrletadd_function_name_definitionnamefuntypinline=letconstr=Constr.make(ConstrNameFuncname)0inadd_constr_definitionconstr(funtyp,[]);letfuntyp={descr=Application{constr;args=[]};pred=Pred.true_}inHashtbl.replacectype_spec.function_mapname{funtyp;inline};;letfunction_of_namename=matchHashtbl.findctype_spec.function_mapnamewith|{funtyp}->Somefuntyp|exceptionNot_found->None(* TODO: Should return a name. *)letfunction_definition_of_namename=Hashtbl.find_optctype_spec.function_mapnameletadd_global_name_definitionnametyp=Hashtbl.replacectype_spec.global_mapnametypletglobal_of_namename=Hashtbl.find_optctype_spec.global_mapnameletget_type_definitions()=ConstrHash.to_seqctype_spec.constr_map|>Seq.filter_map(function|name,(_,[])->Some(Constr.to_stringname)|_->None)|>List.of_seq(*type storing is done*)letexpr_to_symbolexpr=letopenPredinmatchexprwith|Val(Syma)->Variable_lengtha|Constz->Fixed_lengthz|_->failwith"Expression is not a simply symbol"letpp_stringfmts=Format.fprintffmt"\"%s\""s(* Prints a type's description as an OCaml value. *)letrecpp_descr_nameprecedencefmtdescr=letopenFormatinmatchdescrwith|Void->pp_print_stringfmt"void"|Base(sz,name)->fprintffmt"@[<hov 2>%s(%d)@]"name(sz:>int)|Ptr{pointed=typ}->(* | Ptr {pointed = typ; index = Zero} -> *)fprintffmt"@[<hov 2>%a*@]"(pp_type_nameprecedence)typ(* | Ptr {pointed = typ; index} ->
fprintf fmt "@[<hov 2>%a* at %a@]" (pp_type_name precedence) typ pp_index index *)|Structures->fprintffmt"@[<hov 2>struct {@,\
st_byte_size =@ %d;@ st_members =@ @[<v 2>[@ %a@ ]@];@ }@]"(s.st_byte_size:>int)(pp_print_list(funfmt(offset,name,typ)->fprintffmt"(@[<hov 2>%d,@ %a,@ %a@]);"(In_bytes.to_intoffset)pp_stringname(pp_type_name0)typ))s.st_members|StructureFAM{structure;array}->fprintffmt"@[<hov 2>structfam { prefix = %a; array = %a@]"(pp_type_name1)structure(pp_type_name1)array|Array(typ,size)->(ifprecedence>1thenfprintffmt"@[<hov 2>(%a[%a])@]"elsefprintffmt"@[<hov 2>%a[%a]@]")(pp_type_name1)typpp_array_lengthsize|Function{ret;args}->(ifprecedence>0thenfprintffmt"@[<hov 2>(Function (%a, [%a]))@]"elsefprintffmt"@[<hov 2>Function (%a, [%a])@]")(pp_type_name0)ret(pp_print_list~pp_sep:(funfmt()->fprintffmt";@ ")(pp_type_name0))args|Applicationname->pp_namefmtname|Existential{bound_typ;bound_var;body}->fprintffmt"@[<hov 2>∃%s : %a.%a@]"bound_var(pp_type_nameprecedence)bound_typ(pp_type_nameprecedence)body|Unionu->fprintffmt"@[<hov 2>union {@,\
un_byte_size =@ %a;@ un_types =@ @[<v 2>[@ %a@ ]@];@ }@]"Int_option.pretty(u.un_byte_size|>Option.mapIn_bytes.to_int)(pp_print_list(funfmt(name,typ)->fprintffmt"(@[<hov 2>%a,@ %a@]);"pp_stringname(pp_type_name0)typ))u.un_types|Weaktyp->fprintffmt"@[<hov 2>Weak %a@]"(pp_type_nameprecedence)typandpp_constr_nameprecedencefmtconstr=letopenFormatinmatchconstrwithn->fprintffmt"@[<hov 2>%s@]"(Constr.to_stringn)andpp_constr_deffmt(t,params)=letopenFormatinfprintffmt"@[<hov 2>(<%a> %a)@]"(pp_print_list~pp_sep:(funfmt()->fprintffmt",@ ")pp_print_string)params(pp_type_name0)tandpp_type_nameprecedencefmttyp=letopenFormatin(ifprecedence>0thenfprintffmt"@[<hov 2>(%a%a)@]"(pp_descr_name0)typ.descrelsefprintffmt"@[<hov 2>%a%a@]"(pp_descr_nameprecedence)typ.descr)(funfmtp->ifnot@@Pred.is_truepthenfprintffmt"@ with %a"Pred.pppelse())typ.predandpp_namefmt{constr;args}=letopenFormatinmatchargswith|[]->fprintffmt"Name(@[<hov 2>%s@])"(Format.asprintf"%a"Constr.ppconstr)|args->fprintffmt"@[<hov 2>%a(%a)@]"(pp_constr_name0)constr(pp_print_list~pp_sep:(funfmt()->fprintffmt",@ ")Pred.pp_expr)args(* Print the type's name. *)letppfmttyp=pp_type_name0fmttypletpp_constrfmtconstr=pp_constr_name0fmtconstrletprint_constr_mapfmt()=ConstrHash.iter(funnameconstr->Format.fprintffmt"%s %a@."(Constr.to_stringname)pp_constr_defconstr)ctype_spec.constr_mapletprint_function_mapfmt()=Hashtbl.iter(funname{funtyp;inline}->Format.fprintffmt"%s %a@."nameppfuntyp)ctype_spec.function_mapletprint_global_mapfmt()=Hashtbl.iter(funnameglobal->Format.printf"Result: %s -> %a@."nameppglobal)ctype_spec.global_mapletrecsubstitute_in_typetypenv=Log.trace(funp->p"substitute_in_type %a"pptyp)~pp_ret:pp@@fun()->letpred=Pred.substitutestyp.predenvinmatchtyp.descrwith|Void|Base_|Application{args=[]}->{typwithpred=pred}|Structures->letmembers=List.map(fun(ofs,name,typ)->(ofs,name,substitute_in_typetypenv))s.st_membersin{descr=Structure{swithst_members=members};pred}|StructureFAM{structure;array}->{descr=StructureFAM{structure=substitute_in_typestructureenv;array=substitute_in_typearrayenv;};pred;}|Ptr{pointed}->(* does not substitutes further than pointers *){descr=Ptr{pointed=substitute_in_typepointedenv};pred}|Array(elem_typ,Variable_lengths)whenSymbolMap.memsenv->letsz_value=expr_to_symbol(SymbolMap.findsenv)in{descr=Array(substitute_in_typeelem_typenv,sz_value);pred}|Array(elem_typ,sz)->{descr=Array(substitute_in_typeelem_typenv,sz);pred}|Functionfuntyp->letargs=List.map(funt->substitute_in_typetenv)funtyp.argsinletret=substitute_in_typefuntyp.retenvin{descr=Function{funtypwithret;args};pred=pred}|Application{constr;args}->letargs=List.map(funt->Pred.substitutes_exprtenv)argsin{descr=Application{constr;args};pred=pred}|Existential{bound_typ;bound_var;body}->{descr=Existential{bound_typ=substitute_in_typebound_typenv;bound_var;body=substitute_in_typebodyenv};pred}|Unionu->lettypes=List.map(fun(name,typ)->(name,substitute_in_typetypenv))u.un_typesin{descr=Union{uwithun_types=types};pred}|Weak_->assertfalseletsubstitute_in_typetypbindings=letenv=SymbolMap.of_seq@@List.to_seqbindingsinsubstitute_in_typetypenv(* Apply constructor to args, but also perform substitution. *)letapplyconstrargs=Log.trace(funp->p"apply %a %a"Constr.ppconstr(Format.pp_print_listPred.pp_expr)args)~pp_ret:pp@@fun()->lettyp,params=matchconstr_of_nameconstrwithSomex->x|None->raise(Undefined_type_constructor(Constr.to_stringconstr))inletbindings=List.combineparamsargsinsubstitute_in_typetypbindingsletsubstitute_symboltypprevsymb=Log.trace(funp->p"substitute_symbol %s by %s"prevsymb)~pp_ret:pp@@fun()->substitute_in_typetyp[(prev,Pred.(Val(Symsymb)))]letrecinlinedtyp=Log.trace(funp->p"inlined %a"pptyp)~pp_ret:pp@@fun()->matchtyp.descrwith|Application{constr;args}->letres=applyconstrargsininlined{reswithpred=Pred.conjunctiontyp.predres.pred}|_->typletinlined_descrdescr=matchdescrwith(* unify cases*)|Application{constr;args=[]}->lett=matchconstr_of_nameconstrwith|Some(t,_)->t|None->raise(Undefined_type_constructor(Constr.to_stringconstr))in(inlinedt).descr|Application{constr;args}->(inlined(applyconstrargs)).descr|_->descrletcompare_listcmp_eltl1l2=letreccmp=function|[],[]->0|[],_->-1|_,[]->1|h1::t1,h2::t2->letc=cmp_elth1h2inifc=0thencmp(t1,t2)elsecincmp(l1,l2)letreccompare_structs1s2=letc=Stdlib.compares1.st_byte_sizes2.st_byte_sizeinifc=0thencompare_list(fun(i1,_,t1)(i2,_,t2)->comparet1t2)s1.st_memberss2.st_memberselsecandcompare_unionu1u2=letc=Stdlib.compareu1.un_byte_sizeu2.un_byte_sizeinifc=0thencompare_list(fun(_,t1)(_,t2)->comparet1t2)u1.un_typesu2.un_typeselsecandcompare_descrxy=(* let open Format in
fprintf Format.std_formatter "comparing types %a to %a\n" pp_descr x pp_descr y ; *)match(x,y)with|Void,Void->0|Void,_->-1|_,Void->1|Basesz1,Basesz2->Stdlib.comparesz1sz2|Base_,_->-1|_,Base_->1|Structures1,Structures2->compare_structs1s2|Structure_,_->-1|_,Structure_->1|StructureFAMs1,StructureFAMs2->letc=compares1.structures2.structureinifc=0thencompares1.arrays2.arrayelsec|StructureFAM_,_->-1|_,StructureFAM_->1|Ptr{pointed=t},Ptr{pointed=u}->letc=comparetuinif(*only_descr*)false||c<>0thencelse0|Ptr_,_->-1|_,Ptr_->1|Array(t,l),Array(t',l')->letc=(Stdlib.compare:array_length->array_length->int)ll'inifc<>0thencelsecomparett'|Array_,_->-1|_,Array_->1|Function{ret=t;args=ts},Function{ret=u;args=us}->compare_listcompare(t::ts)(u::us)|Application{constr=c1;args=a1},Application{constr=c2;args=a2}->letc=compare_constrc1c2inifc<>0thencelsecompare_list(Stdlib.compare:Pred.expr->Pred.expr->int)a1a2|Application_,_->-1|_,Application_->1|Existential{bound_typ=e1;bound_var=v1;body=i1},Existential{bound_typ=e2;bound_var=v2;body=i2}->letc=Stdlib.comparev1v2inifc<>0thencelse(* let c = compare tv1 tv2 in
if c <> 0 then c
else *)comparei1i2|Existential_,_->-1|_,Existential_->1|Unionu1,Unionu2->compare_unionu1u2|Union_,_->-1|_,Union_->1|Weakt1,Weakt2->comparet1t2|Weak_,_->-1|_,Weak_->1andcompare_constrab=match(a,b)withn1,n2->Constr.comparen1n2andcomparetu=if(* only_descr *)falsethencompare_descrt.descru.descrelseletc1=compare_descrt.descru.descrinifc1<>0thenc1else(Stdlib.compare:Pred.t->Pred.t->int)t.predu.predexceptionUnsizeable_type(* Size in bytes *)letrecsizeof_descrdescr=(* function *)matchinlined_descrdescrwith|Base(sz,_)|Structure{st_byte_size=sz;_}->sz|Ptr_->Units.In_bits.(Codex_config.ptr_size()|>in_bytes)|Array(elem_t,Fixed_lengthsz)->In_bytes.times(Z.to_intsz)(sizeof_descrelem_t.descr)(* | Void -> 4 *)(* TODO : check if this is valid or if a new type should be used behind pointers *)|Void->raise(Failure"The generic type \"void\" is currently not supported")|Array(_,_)|Function_|StructureFAM_->(* Not handled. *)raiseUnsizeable_type(* raise (Invalid_argument "type_size") *)|Application_->assertfalse|Existential{body}->sizeof_descrbody.descr|Union{un_byte_size=Somesz;_}->sz|Union{un_byte_size=None;_}->raiseUnsizeable_type(* raise (Invalid_argument "type_size") *)|Weakt->sizeof_descrt.descrletsizeofx=sizeof_descrx.descrletrecequivxy=match(x.descr,y.descr)with|Void,Void->true|Basesz1,Basesz2->sz1=sz2|Structures1,Structures2->(compare_structs1s2)=0|Ptr{pointed=t;},Ptr{pointed=u}->equivtu|Array(t1,l1),Array(t2,l2)->(l1=l2)&&(equivt1t2)|Function{ret=t;args=ts},Function{ret=u;args=us}->compare_list(funxy->ifequivxythen0else1)(t::ts)(u::us)=0|Application{constr=c1;args=args1},Application{constr=c2;args=args2}whenConstr.equalc1c2->(compare_list(funxy->(Stdlib.compare:Pred.expr->Pred.expr->int)xy)args1args2)=0|Application{constr;args},_->lett=applyconstrargsinequiv{descr=t.descr;pred=Pred.conjunctiont.predx.pred}y|_,Application{constr;args}->lett=applyconstrargsinequivx{descr=t.descr;pred=Pred.conjunctiont.predy.pred}|Weakt1,Weakt2->equivt1t2|_->false(* checks that u is equivalent of t (if u is a subtype of t or vice versa) *)letequiv_descrtu=equiv{descr=t;pred=Pred.true_}{descr=u;pred=Pred.true_}letequal_descrtu=compare_descrtu=0letequaltu=equal_descrt.descru.descr&&((=):Pred.t->Pred.t->bool)t.predu.predletrecis_flexible_arrayt=lett=inlinedtinmatcht.descrwith|StructureFAM_->true|Existential{body}->is_flexible_arraybody|Weak{descr=Array(_,Variable_length_)}->true|Weak_->false|_->falseletrecis_function_pureft=matchft.descrwith|Existential{body}->is_function_purebody|Function{pure}->pure|_->falseletreccontains_descrtu=(* Codex_log.debug "TypedC.contains %a %a" pp_descr t pp_descr u ; *)(* To see : Subtype or Equal *)equiv_descrtu||matchinlined_descrtwith|Void|Base_|Ptr_|Function_->false|Structure{st_members;_}->List.exists(fun(_,_,member)->contains_descrmember.descru)st_members|Array(member,_)->contains_descrmember.descru|StructureFAM{structure;array}->contains_descrstructure.descru||contains_descrarray.descru|Application_->assertfalse|Existential{body}->contains_descrbody.descru|Union{un_types;_}->List.exists(fun(_,typ)->contains_descrtyp.descru)un_types|Weak_->assertfalseletcontainstu=contains_descrt.descru.descrletget_function_names()=List.of_seq@@Hashtbl.to_seq_keysctype_spec.function_map(* Some builtin types; this depend on the data model. *)letbase_typebyte_sizename={descr=Base(byte_size,name);pred=Pred.true_}letword~(byte_size:In_bytes.t)=assertIn_bytes.(zero<byte_size);base_typebyte_size@@"word"^string_of_int(byte_size:>int)lettupletypes=lettotal_size,members=List.fold_left(fun(offset,types)typ->letsize=In_bytes.(offset+sizeoftyp)in(size,(offset,"anon",typ)::types))(In_bytes.zero,[])typesinletdescr=Structure{st_members=List.revmembers;st_byte_size=total_size}in{descr;pred=Pred.true_}(** Additionnal functions used for type domains *)let_concat~(size1:In_bytes.t)~(size2:In_bytes.t)tu=Log.debug(funp->p"TypedC.concat ~size1:%d ~size2:%d of %a and %a"(size1:>int)(size2:>int)pptppu);letpair~size1t~size2u={descr=Structure{st_byte_size=In_bytes.(size1+size2);st_members=[(In_bytes.zero,"anon",t);(size1,"anon",u)];};pred=Pred.true_;}inmatch(t,u)with|({descr=(Structure{st_members=ts_a;_});pred=pred1},{descr=Structure{st_members=ts_b;_};pred=pred2})whenPred.is_truepred1&&Pred.is_truepred2->letts=ts_a@List.map(fun(ofs,_,typ)->(In_bytes.(ofs+size1),"anon",typ))ts_bin{descr=Structure{st_byte_size=In_bytes.(size1+size2);st_members=ts};pred=Pred.true_;}|_,{descr=Structure{st_members=ts_b;_};pred}whenPred.is_truepred->letts=(In_bytes.zero,"anon",t)::List.map(fun(ofs,_,typ)->(In_bytes.(ofs+size1),"anon",typ))ts_bin{descr=Structure{st_byte_size=In_bytes.(size1+size2);st_members=ts};pred=Pred.true_;}|{descr=Structure{st_members=ts_a;_};pred},_whenPred.is_truepred->letts=List.map(fun(ofs,_,typ)->(ofs,"anon",typ))ts_a@[(size1,"anon",u)]in{descr=Structure{st_byte_size=In_bytes.(size1+size2);st_members=ts};pred=Pred.true_;}|_->pair~size1t~size2u(* let rec extract_from_record ~size ~index ~oldsize { st_byte_size; st_members } = *)(* let rec filter lst = *)(* match lst with *)(* | [] -> [] *)(* | ((i, _, t) as a) :: tl when In_bytes.(index <= i && i < index + size) -> *)(* a :: filter tl *)(* | _ :: tl -> filter tl *)(* in *)(* match filter st_members with *)(* | [] -> None *)(* | [ (ofs, _, typ) ] -> Some typ *)(* | (ofs, name, typ) :: tl -> *)(* let l = List.map (fun (i, f, t) -> (In_bytes.(i - ofs), f, t)) tl in *)(* Some *)(* { *)(* descr = *)(* Structure { st_byte_size = size; st_members = (In_bytes.zero, name, typ) :: l }; *)(* pred = Pred.true_; *)(* } *)(* and extract ~(size:In_bits.t) ~(index:In_bits.t) ~(oldsize:In_bits.t) t = *)(* Log.debug (fun p -> *)(* p "TypedC.extract ~size:%d ~index:%d ~oldsize:%d %a" *)(* (size:>int) (index:>int) (oldsize:>int) pp *)(* t); *)(* let t = inlined t in *)(* match t.descr with *)(* | _ when size = In_bits.zero -> None *)(* | _ when sizeof t = size && index = In_bits.zero -> Some t *)(* | Structure ({ st_byte_size = sz; _ } as s) when size < sz && index < sz -> *)(* Option.map *)(* (fun typ -> { typ with pred = Pred.conjunction typ.pred t.pred }) *)(* (extract_from_record ~size ~index ~oldsize s) *)(* | Array (typ, Fixed_length sz) *)(* when index mod sizeof typ = 0 && size = sizeof typ -> *)(* Some typ *)(* | Array (typ, Fixed_length sz) *)(* when let sz = Z.to_int sz in *)(* size < sz && index < sz && index mod sizeof typ = 0 -> *)(* Some { t with descr = Array (typ, Fixed_length (Z.of_int size)) } *)(* | Base (sz, _) when size < sz && index < sz -> Some (word ~byte_size:size) *)(* | _ -> None *)moduleBuild=struct(* TODO: pred should always be != 0, as possibly-null pointers
should be made by union with zero. *)(* TODO: Two builders: one for non-null, one for null pointers. *)(* TODO: Ensure that pointed is a name. *)(* Next step: function pointers as heap pointers. *)letptrpointedpred=(* We should be pointing to a name. *)(matchpointed.predwithPred.True->()|_->assertfalse);ifnot((matchpointed.descrwith(Application_|Weak_)->true|_->false))thenLog.fatal(funp->p"Creating a pointer to %a"pppointed);{descr=Ptr{pointed};pred}letptr_to_name{constr;args}=letpointed={descr=Application{constr;args};pred=Pred.true_}in{descr=Ptr{pointed};pred=Pred.true_}letrefinetyppred={descr=typ.descr;pred=Pred.conjunctionpredtyp.pred}endmoduleParsablePrinter=struct(*dirty hack*)letget_string_of_pointer_predpred=letrecaux=letopenPredinfunction|Cmp(NotEqual,Self,Constzero)->Some"+"|Mutval({value=true},_)->Some"*"|And(t1,t2)->Option.bind(auxt1)(fundefault->Some(Option.value(auxt2)~default))|_->NoneinOption.value(auxpred)~default:"?"letrecppfmt{descr;pred}=letopenFormatinmatchdescrwith|Void->fprintffmt"void"|Structure{st_members}->(pp_print_list~pp_sep:(funp()->fprintfp"@;")(funp(_,field,typ)->fprintfp"%a %s;"pptypfield))fmtst_members|Base(_,name)->fprintffmt"%s"name|StructureFAM_->assertfalse(* TODO: clarify this, we never print p*, which implies that we cant "save" a postfixpoint iteration*)|Ptr{pointed}->fprintffmt"%a%s"pppointed(get_string_of_pointer_predpred)(*| Ptr { pointed; maybe = false } -> fprintf fmt "%a%s" pp pointed (if is_not_null pred then "+" else "?")*)|Array(typ,length)->fprintffmt"%a[%a]"pptyppp_array_lengthlength|Application{constr}->fprintffmt"%s"(Constr.to_stringconstr)|Existential{bound_var;bound_typ;body}->fprintffmt"∃ %s : %a.%a"bound_varppbound_typppbody|Union{un_byte_size;un_types}->fprintffmt"union @[<v>{@;%a@;}@]"(pp_print_list~pp_sep:(funp()->fprintfp"@;")(funp(n,t)->fprintfp"%a %s;"pptn))un_types|Weak_->assertfalse|Function{ret;args}->fprintffmt"[%a]"(pp_print_listpp)(ret::args)letpp_constr_name_deffmt(name,(typ,l))=letopenFormatinmatch(name.name,typ)with|ConstrNamename,_->fprintffmt"type %s = %a;@."namepptyp|ConstrNameFuncf,{descr=Function{ret;args}}->fprintffmt"%a %s(%a);@."ppretf(pp_print_list~pp_sep:(funp()->fprintfp",")(funp(i,t)->fprintfp"%a x_%i"ppt(i+1)))(List.mapi(funit->(i,t))args)|ConstrNameUnion_,_->fprintffmt"todo union@."|ConstrNameStructs,typ->fprintffmt"@.@[<v 2>struct %s {@;%a@]@;};@."spptyp|ConstrNameEnum_,_->fprintffmt"todo enum@."|ConstrNameArray_,_->fprintffmt"todo array@."|ConstrNameFunc_,t->fprintffmt"%a@."pptendletbase_types=["char";"short";"int";"long";"long long";"intmax_t";"uintmax_t";"float";"double";]letprint_specfmt()=ConstrHash.iter(funnameconstr_def->ifList.mem(Constr.to_stringname)base_typesthen()elseFormat.fprintffmt"%a"ParsablePrinter.pp_constr_name_def(name,constr_def))ctype_spec.constr_map