123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213openUtilsopenArch_declopenArch_extraopenProgtype'acallstyle=|StackDirect(* call instruction push the return address on top of the stack *)|ByRegof{call:'aoption;return:bool}(* call instruction store the return address on a register,
- call: (Some r) means that the register is forced to be r
- return:
+ true means that the register is also used for the return
+ false means that there is no constraint (stack is also ok) *)(* TODO: check that we cannot use sth already defined on the Coq side *)moduletypeCore_arch=sigtyperegtyperegxtypexregtyperflagtypecondtypeasm_optypeextra_optypelowering_optionsvalasm_e:(reg,regx,xreg,rflag,cond,asm_op,extra_op)asm_extravalaparams:(reg,regx,xreg,rflag,cond,asm_op,extra_op,lowering_options)Arch_params.architecture_paramsvalcall_conv:(reg,regx,xreg,rflag,cond)calling_conventionvalalloc_stack_need_extra:Z.t->boolvallowering_opt:lowering_optionsvalnot_saved_stack:varlistvalpp_asm:Format.formatter->(reg,regx,xreg,rflag,cond,asm_op)Arch_decl.asm_prog->unitvalcallstyle:regcallstylevalknown_implicits:(Name.t*string)listvalis_ct_asm_op:asm_op->boolvalis_doit_asm_op:asm_op->boolvalis_ct_asm_extra:extra_op->boolvalis_doit_asm_extra:extra_op->boolendmoduletypeArch=sigincludeCore_archvalreg_size:Wsize.wsizevalpointer_data:Wsize.wsizevalmsf_size:Wsize.wsizevalrip:varvalasmOp:(reg,regx,xreg,rflag,cond,asm_op,extra_op)Arch_extra.extended_opSopn.asmOpvalasmOp_sopn:(reg,regx,xreg,rflag,cond,asm_op,extra_op)Arch_extra.extended_opSopn.sopnSopn.asmOpvalreg_vars:varlistvalregx_vars:varlistvalxreg_vars:varlistvalflag_vars:varlistvalargument_vars:varlistvalxmm_argument_vars:varlistvalret_vars:varlistvalxmm_ret_vars:varlistvalallocatable_vars:varlistvalextra_allocatable_vars:varlistvalxmm_allocatable_vars:varlistvalcallee_save_vars:varlistvalnot_saved_stack:varlistvalrsp_var:varvalall_registers:varlistvalsyscall_kill:Sv.tvalcallstyle:varcallstylevalarch_info:(reg,regx,xreg,rflag,cond,asm_op,extra_op)Pretyping.arch_infovalis_ct_sopn:?doit:bool->(reg,regx,xreg,rflag,cond,asm_op,extra_op)Arch_extra.extended_op->boolendmoduleArch_from_Core_arch(A:Core_arch):Archwithtypereg=A.regandtyperegx=A.regxandtypexreg=A.xregandtyperflag=A.rflagandtypecond=A.condandtypeasm_op=A.asm_opandtypeextra_op=A.extra_op=structincludeAletarch_decl=A.asm_e._asm._arch_declletreg_size=arch_decl.reg_sizeletxreg_size=arch_decl.xreg_sizeletpointer_data=arch_pdA.asm_e._asm._arch_declletmsf_size=arch_msfszA.asm_e._asm._arch_declletatoI=A.asm_e._atoI(* not sure it is the best place to define [rip], but we need to know [reg_size] *)letrip=V.mk"RIP"(Reg(Normal,Direct))(tureg_size)L._dummy[]letasmOp=Arch_extra.asm_opIA.asm_eletasmOp_sopn=Sopn.asmOp_sopnpointer_datamsf_sizeasmOpletvar_of_reg(r:reg):var=atoI.toI_r.to_identrletreg_vars:varlist=List.mapvar_of_regarch_decl.toS_r._finC.cenumletvar_of_regx(r:regx):var=atoI.toI_rx.to_identrletregx_vars:varlist=List.mapvar_of_regxarch_decl.toS_rx._finC.cenumletvar_of_xreg(r:xreg):var=atoI.toI_x.to_identrletxreg_vars:varlist=List.mapvar_of_xregarch_decl.toS_x._finC.cenumletvar_of_flag(f:rflag):var=atoI.toI_f.to_identfletflag_vars:varlist=List.mapvar_of_flagarch_decl.toS_f._finC.cenumletcallee_save=call_conv.callee_saved(* Remark the order is very important this register allocation use this list to
allocate register. The lasts in the list are taken only when needed.
So it is better to have callee_saved at the end *)letcallee_save_reg=List.filter_map(Arch_decl.get_ARRegarch_decl)callee_saveletcallee_save_regx=List.filter_map(Arch_decl.get_ARegXarch_decl)callee_saveletcallee_save_xreg=List.filter_map(Arch_decl.get_AXRegarch_decl)callee_saveletrsp=arch_decl.ad_rspletmk_allocatableregscallee_save=List.filter(funr->not(List.memrcallee_save))regs@callee_saveletallocatable=letgood_order=mk_allocatable(Arch_decl.registersarch_decl)callee_save_regin(* be sure that rsp is not used *)List.filter(funr->r<>rsp)good_orderletextra_allocatable=mk_allocatable(Arch_decl.registerxsarch_decl)callee_save_regxletxmm_allocatable=mk_allocatable(Arch_decl.xregistersarch_decl)callee_save_xregletarguments=call_conv.call_reg_argsletxmm_arguments=call_conv.call_xreg_argsletret=call_conv.call_reg_retletxmm_ret=call_conv.call_xreg_retletargument_vars=List.mapvar_of_regargumentsletxmm_argument_vars=List.mapvar_of_xregxmm_argumentsletret_vars=List.mapvar_of_regretletxmm_ret_vars=List.mapvar_of_xregxmm_retletallocatable_vars=List.mapvar_of_regallocatableletextra_allocatable_vars=List.mapvar_of_regxextra_allocatableletxmm_allocatable_vars=List.mapvar_of_xregxmm_allocatableletcallee_save_vars=letvar_of_typed=function|ARRegr->var_of_regr|ARegXr->var_of_regxr|AXRegr->var_of_xregr|ABRegr->var_of_flagrinList.mapvar_of_typedcallee_saveletrsp_var=var_of_regrspletall_registers=reg_vars@regx_vars@xreg_vars@flag_varsletsyscall_kill=Sv.diff(Sv.of_listall_registers)(Sv.of_listcallee_save_vars)letcallstyle=matchA.callstylewith|StackDirect->StackDirect|ByReg{call;return}->ByReg{call=Option.mapvar_of_regcall;return}letarch_info=Pretyping.{pd=reg_size;asmOp=asmOp_sopn;known_implicits=known_implicits;flagnames=List.mapfstknown_implicits;}letis_ct_sopn?(doit=false)(o:(reg,regx,xreg,rflag,cond,asm_op,extra_op)Arch_extra.extended_op)=matchowith|BaseOp(_,o)->(ifdoitthenis_doit_asm_opelseis_ct_asm_op)o|ExtOpo->(ifdoitthenis_doit_asm_extraelseis_ct_asm_extra)oend