123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248openUtilsopenArch_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_opvalasm_e:(reg,regx,xreg,rflag,cond,asm_op,extra_op)asm_extravalaparams:(reg,regx,xreg,rflag,cond,asm_op,extra_op)Arch_params.architecture_paramsvalcall_conv:(reg,regx,xreg,rflag,cond)calling_conventionvalalloc_stack_need_extra:Z.t->boolvalnot_saved_stack:varlistvalpp_asm:Format.formatter->(reg,regx,xreg,rflag,cond,asm_op)Arch_decl.asm_prog->unitvalcallstyle:regcallstyle(* Minimal alignment of every stack frame. Frame sizes are rounded up to
the frame's alignment (see [stack_frame_allocation_size]), so this
bounds the alignment the stack pointer keeps across calls. Armv7-M
forces stack-pointer writes to 4-byte alignment (Arm v7-M Architecture
Reference Manual, B1.5.7); the other architectures have no requirement
beyond the one of the stack slots themselves. *)valsp_min_align:Wsize.wsize(* Widest store the architecture can perform in one instruction. Used to
cap the default stack-zeroization clear step when [sp_min_align]
raises the frame alignment beyond it. *)valmax_store_size:Wsize.wsizevalknown_implicits:(Name.t*string)listvalis_ct_asm_op:asm_op->boolvalis_ct_asm_extra:extra_op->boolvalinternal_call_conv:(reg,regx,xreg,rflag,cond)internal_calling_conventionendmoduletypeArch=sigincludeCore_archtypeextended_op_gen=(asm_op,extra_op)Arch_extra.extended_op_gentypeextended_op=(reg,regx,xreg,rflag,cond,asm_op,extra_op)Arch_extra.extended_opvalreg_size:Wsize.wsizevalpointer_data:Wsize.wsizevalmsf_size:Wsize.wsizevalrip:varvalasmOp:extended_op_genSopn.asmOpvalasmOp_sopn:extended_op_genSopn.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:extended_oparch_infovalis_ct_sopn:?doit:bool->extended_op->boolvalinternal_call_conv:(var,var,var,var,cond)internal_calling_conventionendmoduleArch_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=structincludeAtypeextended_op_gen=(asm_op,extra_op)Arch_extra.extended_op_gentypeextended_op=(reg,regx,xreg,rflag,cond,asm_op,extra_op)Arch_extra.extended_opletarch_decl=A.asm_e._asm._arch_declletreg_size=arch_decl.reg_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}letzero_extend_op(op:extended_op)ws=matchopwith|Arch_extra.BaseOp(None,op')->leto=Arch_extra.BaseOp(Somews,op')inif(asmOp.asm_op_instro).i_validthenSomeoelseNone|_->Noneletarch_info={pd=reg_size;asmOp=asmOp_sopn;zero_extend_op;known_implicits=known_implicits;flagnames=List.mapfstknown_implicits;}letis_ct_sopn?(doit=false)(o:extended_op)=ifdoitthen(Sopn.asm_op_instrasmOpo).Sopn.i_doit=Sopn.DOITelsematchowith|BaseOp(_,o)->is_ct_asm_opo|ExtOpo->is_ct_asm_extraoletinternal_call_conv={icall_reg=List.mapvar_of_reginternal_call_conv.icall_reg;icall_regx=List.mapvar_of_regxinternal_call_conv.icall_regx;icall_xreg=List.mapvar_of_xreginternal_call_conv.icall_xreg;icall_rflag=List.mapvar_of_flaginternal_call_conv.icall_rflag}end