12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232(****************************************************************************)(* Sail *)(* *)(* Sail and the Sail architecture models here, comprising all files and *)(* directories except the ASL-derived Sail code in the aarch64 directory, *)(* are subject to the BSD two-clause licence below. *)(* *)(* The ASL derived parts of the ARMv8.3 specification in *)(* aarch64/no_vector and aarch64/full are copyright ARM Ltd. *)(* *)(* Copyright (c) 2013-2023 *)(* Kathyrn Gray *)(* Shaked Flur *)(* Stephen Kell *)(* Gabriel Kerneis *)(* Robert Norton-Wright *)(* Christopher Pulte *)(* Peter Sewell *)(* Alasdair Armstrong *)(* Brian Campbell *)(* Thomas Bauereiss *)(* Anthony Fox *)(* Jon French *)(* Dominic Mulligan *)(* Stephen Kell *)(* Mark Wassell *)(* Alastair Reid (Arm Ltd) *)(* *)(* All rights reserved. *)(* *)(* This work was partially supported by EPSRC grant EP/K008528/1 <a *)(* href="http://www.cl.cam.ac.uk/users/pes20/rems">REMS: Rigorous *)(* Engineering for Mainstream Systems</a>, an ARM iCASE award, EPSRC IAA *)(* KTF funding, and donations from Arm. This project has received *)(* funding from the European Research Council (ERC) under the European *)(* Union’s Horizon 2020 research and innovation programme (grant *)(* agreement No 789108, ELVER). *)(* *)(* This software was developed by SRI International and the University of *)(* Cambridge Computer Laboratory (Department of Computer Science and *)(* Technology) under DARPA/AFRL contracts FA8650-18-C-7809 ("CIFV") *)(* and FA8750-10-C-0237 ("CTSRD"). *)(* *)(* Redistribution and use in source and binary forms, with or without *)(* modification, are permitted provided that the following conditions *)(* are met: *)(* 1. Redistributions of source code must retain the above copyright *)(* notice, this list of conditions and the following disclaimer. *)(* 2. Redistributions in binary form must reproduce the above copyright *)(* notice, this list of conditions and the following disclaimer in *)(* the documentation and/or other materials provided with the *)(* distribution. *)(* *)(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)(* SUCH DAMAGE. *)(****************************************************************************)openAst_utilopenJibopenJib_utilopenSmt_expletzencode_upper_idid=Util.zencode_upper_string(string_of_idid)letzencode_idid=Util.zencode_string(string_of_idid)letzencode_uid(id,ctyps)=matchctypswith|[]->Util.zencode_string(string_of_idid)|_->Util.zencode_string(string_of_idid^"#"^Util.string_of_list"_"string_of_ctypctyps)(* [required_width n] is the required number of bits to losslessly
represent an integer n *)letrequired_widthn=letrecrequired_width'n=ifBig_int.equalnBig_int.zerothen1else1+required_width'(Big_int.shift_rightn1)inrequired_width'(Big_int.absn)(* Generate SMT definitions in a writer monad that keeps tracks of any
overflow checks needed. *)typechecks={overflows:smt_explist;strings_used:bool;reals_used:bool}letempty_checks={overflows=[];strings_used=false;reals_used=false}letappend_checksc1c2={overflows=c1.overflows@c2.overflows;strings_used=c1.strings_used||c2.strings_used;reals_used=c1.reals_used||c2.reals_used;}type'acheck_writer_state={value:'a;checks:checks}type'acheck_writer=Parse_ast.l->'acheck_writer_stateletreturnx_={value=x;checks=empty_checks}letcurrent_locationl={value=l;checks=empty_checks}letbindmfl=letstate=mlinletstate'=fstate.valuelin{value=state'.value;checks=append_checksstate.checksstate'.checks}letfmapfml=letstate=mlinletvalue=fstate.valuein{value;checks=state.checks}let(let*)=bindlet(let+)mf=fmapfmletrecmapMf=function|[]->return[]|x::xs->let*x=fxinlet*xs=mapMfxsinreturn(x::xs)letrunml=letstate=mlin(state.value,state.checks)letoverflow_checkcheck(_:Parse_ast.l)={value=();checks={empty_checkswithoverflows=[check]}}letstring_used(_:Parse_ast.l)={value=();checks={empty_checkswithstrings_used=true}}letreal_used(_:Parse_ast.l)={value=();checks={empty_checkswithreals_used=true}}(* [signed_size n m exp] takes a smt expression assumed to be a
integer (signed bitvector) of length m and forces it to be length n
by either sign extending it or truncating it as required *)letsigned_size?(checked=true)~into:n~from:msmt=ifn=mthenreturnsmtelseifn>mthenreturn(SignExtend(n,n-m,smt))else(letcheck=(* If the top bit of the truncated number is one *)Ite(Fn("=",[Extract(n-1,n-1,smt);Bitvec_lit[Sail2_values.B1]]),(* Then we have an overflow, unless all bits we truncated were also one *)Fn("not",[Fn("=",[Extract(m-1,n,smt);bvones(m-n)])]),(* Otherwise, all the top bits must be zero *)Fn("not",[Fn("=",[Extract(m-1,n,smt);bvzero(m-n)])]))inlet*_=ifcheckedthenoverflow_checkcheckelsereturn()inreturn(Extract(n-1,0,smt)))(* [unsigned_size n m exp] is much like signed_size, but it assumes
that the bitvector is unsigned, so it either zero extends or
truncates as required. *)letunsigned_size?max_value?(checked=true)~into:n~from:msmt=ifn=mthenreturnsmtelseifn>mthenreturn(Fn("concat",[bvzero(n-m);smt]))else(* Ensure we don't overwrite any high bits when truncating *)let*_=ifcheckedthenoverflow_check(Fn("not",[Fn("=",[Extract(m-1,n,smt);bvzero(m-n)])]))elsereturn()inreturn(Extract(n-1,0,smt))(* We often need to create a SMT bitvector of a length sz with integer
value x. [bvpint sz x] does this for positive integers, and [bvint sz x]
does this for all integers. It's quite awkward because we
don't have a very good way to get the binary representation of
either an OCaml integer or a big integer. *)letbvpint?(loc=Parse_ast.Unknown)szx=letopenSail2_valuesinifBig_int.less_equalBig_int.zerox&&Big_int.less_equalx(Big_int.of_intmax_int)then(letx=Big_int.to_intxinmatchPrintf.sprintf"%X"x|>Util.string_to_list|>List.mapnibble_of_char|>Util.option_allwith|Somenibbles->letbin=List.map(fun(a,b,c,d)->[a;b;c;d])nibbles|>List.concatinlet_,bin=Util.take_drop(functionB0->true|_->false)bininletpadding=List.init(sz-List.lengthbin)(fun_->B0)inBitvec_lit(padding@bin)|None->assertfalse)elseifBig_int.greaterx(Big_int.of_intmax_int)then(lety=refxinletbin=ref[]inwhilenot(Big_int.equal!yBig_int.zero)doletq,m=Big_int.quomod!y(Big_int.of_int2)inbin:=(ifBig_int.equalmBig_int.zerothenB0elseB1)::!bin;y:=qdone;letpadding_size=sz-List.length!bininifpadding_size<0thenraise(Reporting.err_generalloc(Printf.sprintf"Could not create a %d-bit integer with value %s.\nTry increasing the maximum integer size."sz(Big_int.to_stringx)));letpadding=List.initpadding_size(fun_->B0)inBitvec_lit(padding@!bin))elseReporting.unreachableloc__POS__"bvpint called on non-positive integer"letbvintszx=ifBig_int.lessxBig_int.zerothenFn("bvadd",[Fn("bvnot",[bvpintsz(Big_int.absx)]);bvpintsz(Big_int.of_int1)])elsebvpintszx(* [required_width n] is the required number of bits to losslessly
represent an integer n *)letrequired_widthn=letrecrequired_width'n=ifBig_int.equalnBig_int.zerothen1else1+required_width'(Big_int.shift_rightn1)inrequired_width'(Big_int.absn)moduletypeCONFIG=sigvalmax_unknown_integer_width:intvalmax_unknown_bitvector_width:intvalunion_ctyp_classify:ctyp->boolendmoduletypePRIMOP_GEN=sigvalprint_bits:Parse_ast.l->ctyp->stringvalstring_of_bits:Parse_ast.l->ctyp->stringvaldec_str:Parse_ast.l->ctyp->stringvalhex_str:Parse_ast.l->ctyp->stringvalhex_str_upper:Parse_ast.l->ctyp->stringvalcount_leading_zeros:Parse_ast.l->int->stringvalfvector_store:Parse_ast.l->int->ctyp->stringvalis_empty:Parse_ast.l->ctyp->stringvalhd:Parse_ast.l->ctyp->stringvaltl:Parse_ast.l->ctyp->stringendletbuiltin_type_errorfncvalsret_ctyp_opt=let*l=current_locationinletargs=Util.string_of_list", "(funcval->string_of_ctyp(cval_ctypcval))cvalsinmatchret_ctyp_optwith|Someret_ctyp->letmessage=Printf.sprintf"%s : (%s) -> %s"fnargs(string_of_ctypret_ctyp)inraise(Reporting.err_todolmessage)|None->raise(Reporting.err_todol(Printf.sprintf"%s : (%s)"fnargs))moduleMake(Config:CONFIG)(Primop_gen:PRIMOP_GEN)=structletlint_size=Config.max_unknown_integer_widthletlbits_size=Config.max_unknown_bitvector_widthletlbits_index=required_width(Big_int.of_int(lbits_size-1))letint_size=function|CT_constantn->required_widthn|CT_fintsz->sz|CT_lint->lint_size|_->Reporting.unreachableParse_ast.Unknown__POS__"Argument to int_size must be an integer type"letbv_size=function|CT_fbitssz|CT_sbitssz->sz|CT_lbits->lbits_size|_->Reporting.unreachableParse_ast.Unknown__POS__"Argument to bv_size must be a bitvector type"letto_fbitsctypbv=matchctypwith|CT_fbitsn->(n,bv)|CT_lbits->(lbits_size,Fn("contents",[bv]))|_->Reporting.unreachableParse_ast.Unknown__POS__(Printf.sprintf"Type %s must be a bitvector in to_fbits"(string_of_ctypctyp))letliteralvlctyp=letopenValue2inmatch(vl,ctyp)with|VL_bitsbv,CT_fbitsn->unsigned_size~into:n~from:(List.lengthbv)(Bitvec_litbv)|VL_boolb,_->return(Bool_litb)|VL_intn,CT_constantm->return(bvint(required_widthn)n)|VL_intn,CT_fintsz->return(bvintszn)|VL_intn,CT_lint->return(bvintConfig.max_unknown_integer_widthn)|VL_bitb,CT_bit->return(Bitvec_lit[b])|VL_unit,_->return(Enum"unit")|VL_stringstr,_->let*_=string_usedinreturn(String_litstr)|VL_realstr,_->let*_=real_usedinreturn(ifstr.[0]='-'thenFn("-",[Real_lit(String.substr1(String.lengthstr-1))])elseReal_litstr)|VL_refstr,_->return(Fn("reg_ref",[String_litstr]))|_->let*l=current_locationinReporting.unreachablel__POS__("Cannot translate literal to SMT: "^string_of_valuevl^" : "^string_of_ctypctyp)letsmt_cval_callopargs=match(op,args)with|Bnot,[arg]->Fn("not",[arg])|Bor,[arg]->arg|Bor,args->Fn("or",args)|Band,[arg]->arg|Band,args->Fn("and",args)|Eq,args->Fn("=",args)|Neq,args->Fn("not",[Fn("=",args)])|Ilt,[lhs;rhs]->Fn("bvslt",[lhs;rhs])|Ilteq,[lhs;rhs]->Fn("bvsle",[lhs;rhs])|Igt,[lhs;rhs]->Fn("bvsgt",[lhs;rhs])|Igteq,[lhs;rhs]->Fn("bvsge",[lhs;rhs])|Iadd,args->Fn("bvadd",args)|Isub,args->Fn("bvsub",args)|Bvnot,args->Fn("bvnot",args)|Bvor,args->Fn("bvor",args)|Bvand,args->Fn("bvand",args)|Bvxor,args->Fn("bvxor",args)|Bvadd,args->Fn("bvadd",args)|Bvsub,args->Fn("bvsub",args)|Concat,args->Fn("concat",args)|Zero_extend_,_->failwith"ZE"|Sign_extend_,_->failwith"SE"|Slice_,_->failwith"slice"|Sslice_,_->failwith"sslice"|Set_slice,_->failwith"set_slice"|Replicate_,_->failwith"replicate"|List_hd,[arg]->Fn("hd",[arg])|op,_->failwith(string_of_opop)letrecsmt_cvalcval=matchcval_ctypcvalwith|CT_constantn->return(bvint(required_widthn)n)|_->(matchcvalwith|V_lit(vl,ctyp)->literalvlctyp|V_id(id,_)->return(Varid)|V_call(List_hd,[arg])->let*l=current_locationinletop=Primop_gen.hdl(cval_ctyparg)inlet*arg=smt_cvalarginreturn(Hd(op,arg))|V_call(List_tl,[arg])->let*l=current_locationinletop=Primop_gen.tll(cval_ctyparg)inlet*arg=smt_cvalarginreturn(Tl(op,arg))|V_call(List_is_empty,[arg])->let*l=current_locationinletop=Primop_gen.is_emptyl(cval_ctyparg)inlet*arg=smt_cvalarginreturn(Fn(op,[arg]))|V_call(op,args)->let*args=mapMsmt_cvalargsinreturn(smt_cval_callopargs)|V_ctor_kind(union,ctor,_)->let*union=smt_cvalunioninreturn(Fn("not",[Tester(zencode_uidctor,union)]))|V_ctor_unwrap(union,(ctor,_),_)->letunion_ctyp=cval_ctypunioninlet*union=smt_cvalunioninreturn(Unwrap(ctor,Config.union_ctyp_classifyunion_ctyp,union))|V_field(record,field)->beginmatchcval_ctyprecordwith|CT_struct(struct_id,_)->let*record=smt_cvalrecordinreturn(Field(struct_id,field,record))|_->failwith"Field for non-struct type"end|cval->return(Var(Name(mk_id"UNKNOWN",-1)))(* failwith ("Unrecognised cval " ^ string_of_cval cval) *))(* [bvzeint esz cval] (BitVector Zero Extend INTeger), takes a cval
which must be an integer type (either CT_fint, or CT_lint), and
produces a bitvector which is either zero extended or truncated to
exactly esz bits. *)letbvzeinteszcval=letsz=int_size(cval_ctypcval)inmatchcvalwith|V_lit(VL_intn,_)->return(bvinteszn)|_->let*smt=smt_cvalcvalinreturn(ifesz=szthensmtelseifesz>szthenFn("concat",[bvzero(esz-sz);smt])elseExtract(esz-1,0,smt))letbuiltin_arithfnbig_int_fnpaddingv1v2ret_ctyp=match(cval_ctypv1,cval_ctypv2,ret_ctyp)with|_,_,CT_constantc->return(bvint(required_widthc)c)|CT_constantc1,CT_constantc2,_->return(bvint(int_sizeret_ctyp)(big_int_fnc1c2))|ctyp1,ctyp2,_->(* To detect arithmetic overflow we can expand the input
bitvectors to some size determined by a padding function,
then check we don't lose precision when going back after
performing the operation. *)letret_sz=int_sizeret_ctypinlet*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inlet*padded_smt1=signed_size~into:(paddingret_sz)~from:(int_sizectyp1)smt1inlet*padded_smt2=signed_size~into:(paddingret_sz)~from:(int_sizectyp2)smt2insigned_size~into:ret_sz~from:(paddingret_sz)(Fn(fn,[padded_smt1;padded_smt2]))letbuiltin_add_int=builtin_arith"bvadd"Big_int.add(funx->x+1)letbuiltin_sub_int=builtin_arith"bvsub"Big_int.sub(funx->x+1)letbuiltin_mult_int=builtin_arith"bvmul"Big_int.mul(funx->x*2)letbuiltin_neg_intvret_ctyp=match(cval_ctypv,ret_ctyp)with|_,CT_constantc->return(bvint(required_widthc)c)|CT_constantc,_->return(bvint(int_sizeret_ctyp)(Big_int.negatec))|ctyp,_->letopenSail2_valuesinlet*smt=bind(smt_cvalv)(signed_size~into:(int_sizeret_ctyp)~from:(int_sizectyp))inlet*_=overflow_check(Fn("=",[smt;Bitvec_lit(B1::List.init(int_sizeret_ctyp-1)(fun_->B0))]))inreturn(Fn("bvneg",[smt]))letbuiltin_abs_intvret_ctyp=match(cval_ctypv,ret_ctyp)with|_,CT_constantc->return(bvint(required_widthc)c)|CT_constantc,_->return(bvint(int_sizeret_ctyp)(Big_int.absc))|ctyp,_->letsz=int_sizectypinlet*smt=smt_cvalvinlet*resized_pos=signed_size~into:(int_sizeret_ctyp)~from:szsmtinlet*resized_neg=signed_size~into:(int_sizeret_ctyp)~from:sz(bvnegsmt)inreturn(Ite(Fn("=",[Extract(sz-1,sz-1,smt);bvone1]),resized_neg,resized_pos))letbuiltin_choose_intcompareopv1v2ret_ctyp=match(cval_ctypv1,cval_ctypv2)with|CT_constantn,CT_constantm->return(bvint(int_sizeret_ctyp)(opnm))|ctyp1,ctyp2->letret_sz=int_sizeret_ctypinlet*smt1=bind(smt_cvalv1)(signed_size~into:ret_sz~from:(int_sizectyp1))inlet*smt2=bind(smt_cvalv2)(signed_size~into:ret_sz~from:(int_sizectyp2))inreturn(Ite(Fn(compare,[smt1;smt2]),smt1,smt2))letbuiltin_max_int=builtin_choose_int"bvsgt"maxletbuiltin_min_int=builtin_choose_int"bvslt"minletsmt_conversion~into:to_ctyp~from:from_ctypx=match(from_ctyp,to_ctyp)with|_,_whenctyp_equalfrom_ctypto_ctyp->returnx|_,CT_constantc->return(bvint(required_widthc)c)|CT_constantc,CT_fintsz->return(bvintszc)|CT_constantc,CT_lint->return(bvintlint_sizec)|CT_fintsz,CT_lint->signed_size~into:lint_size~from:szx|CT_lint,CT_fintsz->signed_size~into:sz~from:lint_sizex|CT_lint,CT_fbitsn->signed_size~into:n~from:lint_sizex|CT_lint,CT_lbits->let*x=signed_size~into:lbits_size~from:lint_sizexinreturn(Fn("Bits",[bvintlbits_index(Big_int.of_intlint_size);x]))|CT_fintn,CT_lbits->let*x=signed_size~into:lbits_size~from:nxinreturn(Fn("Bits",[bvintlbits_index(Big_int.of_intn);x]))|CT_lbits,CT_fbitsn->unsigned_size~into:n~from:lbits_size(Fn("contents",[x]))|CT_fbitsn,CT_fbitsm->unsigned_size~into:m~from:nx|CT_fbitsn,CT_lbits->let*x=unsigned_size~into:lbits_size~from:nxinreturn(Fn("Bits",[bvintlbits_index(Big_int.of_intn);x]))|_,_->let*l=current_locationinReporting.unreachablel__POS__(Printf.sprintf"Cannot perform conversion from %s to %s"(string_of_ctypfrom_ctyp)(string_of_ctypto_ctyp))letint_comparisonfnbig_int_fnv1v2=let*sv1=smt_cvalv1inlet*sv2=smt_cvalv2inmatch(cval_ctypv1,cval_ctypv2)with|CT_constantc1,CT_constantc2->return(Bool_lit(big_int_fnc1c2))|CT_lint,CT_lint->return(Fn(fn,[sv1;sv2]))|CT_fintsz1,CT_fintsz2->return(ifsz1==sz2thenFn(fn,[sv1;sv2])elseifsz1>sz2thenFn(fn,[sv1;SignExtend(sz1,sz1-sz2,sv2)])elseFn(fn,[SignExtend(sz2,sz2-sz1,sv1);sv2]))|CT_constantc,CT_fintsz->return(Fn(fn,[bvintszc;sv2]))|CT_fintsz,CT_constantc->return(Fn(fn,[sv1;bvintszc]))|CT_constantc,CT_lint->return(Fn(fn,[bvintlint_sizec;sv2]))|CT_lint,CT_constantc->return(Fn(fn,[sv1;bvintlint_sizec]))|CT_fintsz,CT_lintwhensz<lint_size->return(Fn(fn,[SignExtend(lint_size,lint_size-sz,sv1);sv2]))|CT_lint,CT_fintszwhensz<lint_size->return(Fn(fn,[sv1;SignExtend(lint_size,lint_size-sz,sv2)]))|_,_->builtin_type_errorfn[v1;v2]Noneletbuiltin_eq_int=int_comparison"="Big_int.equalletbuiltin_lt=int_comparison"bvslt"Big_int.lessletbuiltin_lteq=int_comparison"bvsle"Big_int.less_equalletbuiltin_gt=int_comparison"bvsgt"Big_int.greaterletbuiltin_gteq=int_comparison"bvsge"Big_int.greater_equalletbuiltin_signedvret_ctyp=let*sv=smt_cvalvinmatch(cval_ctypv,ret_ctyp)with|CT_fbitsn,CT_fintmwhenm>=n->return(SignExtend(m,m-n,sv))|CT_fbitsn,CT_lint->return(SignExtend(lint_size,lint_size-n,sv))|CT_lbits,CT_lint->letcontents=Fn("contents",[sv])inlettop_bit_shift=ZeroExtend(lbits_size,lbits_index,bvsub(Fn("len",[sv]))(bvonelbits_index))inlettop_bit=Extract(0,0,bvlshrcontentstop_bit_shift)inletis_signed=Fn("=",[top_bit;bvone1])inlet*zero_extended=unsigned_size~into:lint_size~from:lbits_sizecontentsinletones_mask=bvshl(bvoneslint_size)(ZeroExtend(lint_size,lbits_index,Fn("len",[sv])))inletones_extended=bvorones_maskzero_extendedinreturn(Ite(is_signed,ones_extended,zero_extended))|_,_->builtin_type_error"signed"[v](Someret_ctyp)letbuiltin_unsignedvret_ctyp=let*sv=smt_cvalvinmatch(cval_ctypv,ret_ctyp)with|CT_fbitsn,CT_fintmwhenm>n->return(Fn("concat",[bvzero(m-n);sv]))|CT_fbitsn,CT_lint->return(Fn("concat",[bvzero(lint_size-n);sv]))|CT_lbits,CT_lint->signed_size~into:lint_size~from:lbits_size(Fn("contents",[sv]))|CT_lbits,CT_fintm->signed_size~into:m~from:lbits_size(Fn("contents",[sv]))|_,_->builtin_type_error"unsigned"[v](Someret_ctyp)letbvmasklen=letall_ones=bvoneslbits_sizeinletshift=Fn("concat",[bvzero(lbits_size-lbits_index);len])inbvnot(bvshlall_onesshift)letbuiltin_shiftshiftopvbitsvshiftret_ctyp=matchcval_ctypvbitswith|CT_fbitsn->let*bv=smt_cvalvbitsinlet*shift=bvzeintnvshiftinreturn(Fn(shiftop,[bv;shift]))|CT_lbits->let*bv=smt_cvalvbitsinlet*shift=bvzeintlbits_sizevshiftinletshifted=ifshiftop="bvashr"then(letmask=bvmask(Fn("len",[bv]))inbvandmask(Fn(shiftop,[bvor(bvnotmask)(Fn("contents",[bv]));shift])))elseFn(shiftop,[Fn("contents",[bv]);shift])inreturn(Fn("Bits",[Fn("len",[bv]);shifted]))|_->builtin_type_errorshiftop[vbits;vshift](Someret_ctyp)letbuiltin_slicev1v2v3ret_ctyp=match(cval_ctypv1,cval_ctypv2,cval_ctypv3,ret_ctyp)with|CT_lbits,CT_constantstart,CT_constantlen,CT_fbits_->lettop=Big_int.pred(Big_int.addstartlen)inlet*v1=smt_cvalv1inreturn(Extract(Big_int.to_inttop,Big_int.to_intstart,Fn("contents",[v1])))|CT_fbits_,CT_constantstart,CT_constantlen,CT_fbits_->lettop=Big_int.pred(Big_int.addstartlen)inlet*v1=smt_cvalv1inreturn(Extract(Big_int.to_inttop,Big_int.to_intstart,v1))|CT_fbits_,CT_fint_,CT_constantlen,CT_fbits_->let*shifted=builtin_shift"bvlshr"v1v2(cval_ctypv1)inreturn(Extract(Big_int.to_int(Big_int.predlen),0,shifted))|ctyp1,ctyp2,_,CT_lbits->let*smt1=smt_cvalv1inletsz,smt1=to_fbitsctyp1smt1inlet*smt1=unsigned_size~into:lbits_size~from:szsmt1inlet*smt2=bind(smt_cvalv2)(signed_size~into:lbits_size~from:(int_sizectyp2))inlet*smt3=bvzeintlbits_indexv3inreturn(Fn("Bits",[smt3;Fn("bvand",[Fn("bvlshr",[smt1;smt2]);bvmasksmt3])]))|_->builtin_type_error"slice"[v1;v2;v3](Someret_ctyp)letbuiltin_zerosvret_ctyp=match(cval_ctypv,ret_ctyp)with|_,CT_fbitsn->return(bvzeron)|CT_constantc,CT_lbits->return(Fn("Bits",[bvintlbits_indexc;bvzerolbits_size]))|ctyp,CT_lbitswhenint_sizectyp>=lbits_index->let*v=smt_cvalvinreturn(Fn("Bits",[extract(lbits_index-1)0v;bvzerolbits_size]))|_->builtin_type_error"zeros"[v](Someret_ctyp)letbuiltin_onescval=function|CT_fbitsn->return(bvonesn)|CT_lbits->let*v=smt_cvalcvalinletlen=extract(lbits_index-1)0vinreturn(Fn("Bits",[len;Fn("bvand",[bvmasklen;bvoneslbits_size])]))|ret_ctyp->builtin_type_error"ones"[cval](Someret_ctyp)letbuiltin_zero_extendvbitsvlenret_ctyp=match(cval_ctypvbits,cval_ctypvlen,ret_ctyp)with|CT_fbitsn,_,CT_fbitsmwhenn=m->smt_cvalvbits|CT_fbitsn,_,CT_fbitsm->let*bv=smt_cvalvbitsinreturn(Fn("concat",[bvzero(m-n);bv]))|CT_fbitsn,CT_fintm,CT_lbits->let*bv=smt_cvalvbitsinreturn(Fn("concat",[bvzero(m-n);bv]))|CT_lbits,_,CT_fbitsm->let*bv=smt_cvalvbitsinreturn(Extract(m-1,0,Fn("contents",[bv])))(*
| CT_fbits n, CT_lbits ->
assert (lbits_size ctx >= n);
let vbits =
if lbits_size ctx = n then smt_cval ctx vbits
else if lbits_size ctx > n then Fn ("concat", [bvzero (lbits_size ctx - n); smt_cval ctx vbits])
else assert false
in
Fn ("Bits", [bvzeint ctx ctx.lbits_index vlen; vbits])
*)|CT_lbits,CT_lint,CT_lbits->let*len=smt_cvalvleninlet*bv=smt_cvalvbitsinreturn(Fn("Bits",[extract(lbits_index-1)0len;Fn("contents",[bv])]))|_->builtin_type_error"zero_extend"[vbits;vlen](Someret_ctyp)letbuiltin_sign_extendvbitsvlenret_ctyp=let*bv=smt_cvalvbitsinmatch(cval_ctypvbits,cval_ctypvlen,ret_ctyp)with|CT_fbitsn,_,CT_fbitsmwhenn=m->smt_cvalvbits|CT_fbitsn,_,CT_fbitsm->lettop_bit_one=Fn("=",[Extract(n-1,n-1,bv);bvone1])inreturn(Ite(top_bit_one,Fn("concat",[bvones(m-n);bv]),Fn("concat",[bvzero(m-n);bv])))|CT_lbits,i_ctyp,CT_lbits->let*len=smt_cvalvleninletcontents=Fn("contents",[bv])inlettop_bit_shift=ZeroExtend(lbits_size,lbits_index,bvsub(Fn("len",[bv]))(bvonelbits_index))inlettop_bit=Extract(0,0,bvlshrcontentstop_bit_shift)inletis_signed=Fn("=",[top_bit;bvone1])inlet*new_len=signed_size~into:lbits_index~from:(int_sizei_ctyp)leninletzero_extended=Fn("Bits",[new_len;contents])inletones_mask=bvshl(bvoneslbits_size)(ZeroExtend(lbits_size,lbits_index,Fn("len",[bv])))inletunused_mask=bvnot(bvshl(bvoneslbits_size)(ZeroExtend(lbits_size,lbits_index,new_len)))inletones_extended=Fn("Bits",[new_len;bvandunused_mask(bvorones_maskcontents)])inreturn(Ite(is_signed,ones_extended,zero_extended))|_->builtin_type_error"sign_extend"[vbits;vlen](Someret_ctyp)letbuiltin_replicate_bitsvbitsvtimesret_ctyp=match(cval_ctypvbits,cval_ctypvtimes,ret_ctyp)with|CT_fbitsn,_,CT_fbitsm->let*bits=smt_cvalvbitsinlettimes=m/ninreturn(Fn("concat",List.inittimes(fun_->bits)))|CT_fbitsn,vtimes_ctyp,CT_lbits->letmax_times=(lbits_size/n)+1inlet*times=bind(smt_cvalvtimes)(signed_size~into:lbits_index~from:(int_sizevtimes_ctyp))inletlen=bvmul(bvpintlbits_index(Big_int.of_intn))timesinlet*bits=smt_cvalvbitsinletcontents=Extract(lbits_size-1,0,Fn("concat",List.initmax_times(fun_->bits)))inreturn(Fn("Bits",[len;Fn("bvand",[bvmasklen;contents])]))|CT_lbits,vtimes_ctyp,CT_lbits->let*bits=smt_cvalvbitsinlet*times=bind(smt_cvalvtimes)(signed_size~into:lbits_index~from:(int_sizevtimes_ctyp))inletnew_len=bvmul(Fn("len",[bits]))timesin(* This is extremely inefficient, but we don't have a good alternative if we find ourselves in this case. *)letshifted=List.init(lbits_size-1)(funn->letamount=bvmul(bvpintlbits_size(Big_int.of_int(n+1)))(ZeroExtend(lbits_size,lbits_index,Fn("len",[bits])))inbvshl(Fn("contents",[bits]))amount)inletcontents=List.fold_leftbvor(Fn("contents",[bits]))shiftedinreturn(Fn("Bits",[new_len;Fn("bvand",[bvmasknew_len;contents])]))|_->builtin_type_error"replicate_bits"[vbits;vtimes](Someret_ctyp)letbuiltin_not_bitsvret_ctyp=match(cval_ctypv,ret_ctyp)with|CT_lbits,CT_fbitsn->let*bv=smt_cvalvinreturn(bvnot(Extract(n-1,0,Fn("contents",[bv]))))|CT_lbits,CT_lbits->let*bv=smt_cvalvinletlen=Fn("len",[bv])inreturn(Fn("Bits",[len;Fn("bvand",[bvmasklen;bvnot(Fn("contents",[bv]))])]))|CT_fbitsn,CT_fbitsmwhenn=m->let*bv=smt_cvalvinreturn(bvnotbv)|_,_->builtin_type_error"not_bits"[v](Someret_ctyp)letbuiltin_lengthvret_ctyp=match(cval_ctypv,ret_ctyp)with|_,CT_constantlen->return(bvpint(int_sizeret_ctyp)len)|CT_fbitsn,_->return(bvpint(int_sizeret_ctyp)(Big_int.of_intn))|CT_lbits,_->let*bv=smt_cvalvinunsigned_size~into:(int_sizeret_ctyp)~from:lbits_index(Fn("len",[bv]))|_->builtin_type_error"length"[v](Someret_ctyp)letbuiltin_arith_bitsopv1v2ret_ctyp=let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inmatch(cval_ctypv1,cval_ctypv2,ret_ctyp)with|CT_fbitsn,CT_fbitsm,CT_fbitso->(* The Sail type system should guarantee this *)assert(n=m&&m=o);return(Fn(op,[smt1;smt2]))|CT_lbits,CT_lbits,CT_lbits->return(Fn("Bits",[Fn("len",[smt1]);Fn(op,[Fn("contents",[smt1]);Fn("contents",[smt2])])]))|_->builtin_type_error("arith_bits "^op)[v1;v2](Someret_ctyp)letbuiltin_arith_bits_intopv1v2ret_ctyp=let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inmatch(cval_ctypv1,cval_ctypv2,ret_ctyp)with|CT_fbitsn,CT_constantc,CT_fbitso->assert(n=o);return(Fn(op,[smt1;bvintoc]))|CT_fbitsn,CT_fintm,CT_fbitso->assert(n=o);let*smt2=signed_size~into:o~from:msmt2inreturn(Fn(op,[smt1;smt2]))|CT_fbitsn,CT_lint,CT_fbitso->assert(n=o);let*smt2=signed_size~into:o~from:lint_sizesmt2inreturn(Fn(op,[smt1;smt2]))|CT_lbits,v2_ctyp,CT_lbits->let*smt2=signed_size~into:lbits_size~from:(int_sizev2_ctyp)smt2inreturn(Fn("Bits",[Fn("len",[smt1]);Fn(op,[Fn("contents",[smt1]);smt2])]))|_->builtin_type_error("arith_bits_int "^op)[v1;v2](Someret_ctyp)letbuiltin_eq_bitsv1v2=match(cval_ctypv1,cval_ctypv2)with|CT_fbitsn,CT_fbitsm->leto=maxnminlet*smt1=bind(smt_cvalv1)(unsigned_size~into:o~from:n)inlet*smt2=bind(smt_cvalv2)(unsigned_size~into:o~from:n)inreturn(Fn("=",[smt1;smt2]))|CT_lbits,CT_lbits->let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inletlen1=Fn("len",[smt1])inletcontents1=Fn("contents",[smt1])inletlen2=Fn("len",[smt2])inletcontents2=Fn("contents",[smt2])inreturn(Fn("and",[Fn("=",[len1;len2]);Fn("=",[Fn("bvand",[bvmasklen1;contents1]);Fn("bvand",[bvmasklen2;contents2])]);]))|CT_lbits,CT_fbitsn->let*smt1=bind(smt_cvalv1)(funbv->unsigned_size~into:n~from:lbits_size(Fn("contents",[bv])))inlet*smt2=smt_cvalv2inreturn(Fn("=",[smt1;smt2]))|CT_fbitsn,CT_lbits->let*smt1=smt_cvalv1inlet*smt2=bind(smt_cvalv2)(funbv->unsigned_size~into:n~from:lbits_size(Fn("contents",[bv])))inreturn(Fn("=",[smt1;smt2]))|_->builtin_type_error"eq_bits"[v1;v2]Noneletbuiltin_neq_bitsv1v2=let*t=builtin_eq_bitsv1v2inreturn(Fn("not",[t]))letbuiltin_appendv1v2ret_ctyp=match(cval_ctypv1,cval_ctypv2,ret_ctyp)with|CT_fbitsn,CT_fbitsm,CT_fbitso->assert(n+m=o);let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inreturn(Fn("concat",[smt1;smt2]))|CT_fbitsn,CT_lbits,CT_lbits->let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inletx=Fn("concat",[bvzero(lbits_size-n);smt1])inletshift=Fn("concat",[bvzero(lbits_size-lbits_index);Fn("len",[smt2])])inreturn(Fn("Bits",[bvadd(bvintlbits_index(Big_int.of_intn))(Fn("len",[smt2]));bvor(bvshlxshift)(Fn("contents",[smt2]));]))|CT_lbits,CT_fbitsn,CT_fbitsm->let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inreturn(Extract(m-1,0,Fn("concat",[Fn("contents",[smt1]);smt2])))(*
| CT_lbits, CT_fbits n, CT_lbits ->
let smt1 = smt_cval ctx v1 in
let smt2 = smt_cval ctx v2 in
Fn
( "Bits",
[
bvadd (bvint ctx.lbits_index (Big_int.of_int n)) (Fn ("len", [smt1]));
Extract (lbits_size ctx - 1, 0, Fn ("concat", [Fn ("contents", [smt1]); smt2]));
]
)
| CT_fbits n, CT_fbits m, CT_lbits ->
let smt1 = smt_cval ctx v1 in
let smt2 = smt_cval ctx v2 in
Fn
( "Bits",
[
bvint ctx.lbits_index (Big_int.of_int (n + m));
unsigned_size ctx (lbits_size ctx) (n + m) (Fn ("concat", [smt1; smt2]));
]
)
*)|CT_lbits,CT_lbits,CT_lbits->let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inletx=Fn("contents",[smt1])inletshift=Fn("concat",[bvzero(lbits_size-lbits_index);Fn("len",[smt2])])inreturn(Fn("Bits",[bvadd(Fn("len",[smt1]))(Fn("len",[smt2]));bvor(bvshlxshift)(Fn("contents",[smt2]))]))(*
| CT_lbits, CT_lbits, CT_fbits n ->
let smt1 = smt_cval ctx v1 in
let smt2 = smt_cval ctx v2 in
let x = Fn ("contents", [smt1]) in
let shift = Fn ("concat", [bvzero (lbits_size ctx - ctx.lbits_index); Fn ("len", [smt2])]) in
unsigned_size ctx n (lbits_size ctx) (bvor (bvshl x shift) (Fn ("contents", [smt2])))
*)|_->builtin_type_error"append"[v1;v2](Someret_ctyp)letbuiltin_sail_truncatev1v2ret_ctyp=match(cval_ctypv1,cval_ctypv2,ret_ctyp)with|v1_ctyp,CT_constantc,CT_fbitsm->let*smt1=smt_cvalv1inletsz,bv=to_fbitsv1_ctypsmt1inassert(Big_int.to_intc=m&&m<=sz);return(Extract(Big_int.to_intc-1,0,bv))|v1_ctyp,_,CT_lbits->let*smt1=smt_cvalv1inletsz,bv=to_fbitsv1_ctypsmt1inlet*smt1=unsigned_size~into:lbits_size~from:szbvinlet*smt2=bvzeintlbits_indexv2inreturn(Fn("Bits",[smt2;Fn("bvand",[bvmasksmt2;smt1])]))|_->builtin_type_error"sail_truncate"[v1;v2](Someret_ctyp)letbuiltin_sail_truncateLSBv1v2ret_ctyp=match(cval_ctypv1,cval_ctypv2,ret_ctyp)with|v1_ctyp,CT_constantc,CT_fbitsm->let*smt1=smt_cvalv1inletsz,bv=to_fbitsv1_ctypsmt1inassert(Big_int.to_intc=m&&m<=sz);return(Extract(sz-1,sz-Big_int.to_intc,bv))|CT_fbitssz,_,CT_lbits->let*smt1=smt_cvalv1inlet*len=bvzeintlbits_indexv2inletshift=bvsub(bvpintlbits_index(Big_int.of_intsz))leninletshifted=bvlshrsmt1(ZeroExtend(sz,lbits_index,shift))inlet*shifted=unsigned_size~checked:false~into:lbits_size~from:szshiftedinreturn(Fn("Bits",[len;shifted]))|CT_lbits,_,CT_lbits->let*smt1=smt_cvalv1inlet*len=bvzeintlbits_indexv2inletshift=bvsub(Fn("len",[smt1]))leninletshifted=bvlshr(Fn("contents",[smt1]))(ZeroExtend(lbits_size,lbits_index,shift))inreturn(Fn("Bits",[len;shifted]))|_->builtin_type_error"sail_truncateLSB"[v1;v2](Someret_ctyp)letbuiltin_bitwisefnv1v2ret_ctyp=match(cval_ctypv1,cval_ctypv2,ret_ctyp)with|CT_fbitsn,CT_fbitsm,CT_fbitso->assert(n=m&&m=o);let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inreturn(Fn(fn,[smt1;smt2]))|CT_lbits,CT_lbits,CT_lbits->let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inreturn(Fn("Bits",[Fn("len",[smt1]);Fn(fn,[Fn("contents",[smt1]);Fn("contents",[smt2])])]))|_->builtin_type_errorfn[v1;v2](Someret_ctyp)letfbits_maskmask_szlen=bvnot(bvshl(bvonesmask_sz)len)letbuiltin_vector_accessveciret_ctyp=match(cval_ctypvec,cval_ctypi,ret_ctyp)with|CT_fbitsn,CT_constanti,CT_bit->let*bv=smt_cvalvecinreturn(Extract(Big_int.to_inti,Big_int.to_inti,bv))|CT_lbits,CT_constanti,CT_bit->let*bv=smt_cvalvecinreturn(Extract(Big_int.to_inti,Big_int.to_inti,Fn("contents",[bv])))|((CT_lbits|CT_fbits_)asbv_ctyp),i_ctyp,CT_bit->let*bv=smt_cvalvecinletsz,bv=to_fbitsbv_ctypbvinlet*i=smt_cvaliin(* checked:false should be fine here, as the Sail type system has already checked the bounds *)let*shift=signed_size~checked:false~into:sz~from:(int_sizei_ctyp)iinreturn(Extract(0,0,Fn("bvlshr",[bv;shift])))|CT_fvector(len,_),i_ctyp,_->let*vec=smt_cvalvecinlet*i=bind(smt_cvali)(unsigned_size~checked:false~into:(required_width(Big_int.of_int(len-1))-1)~from:(int_sizei_ctyp))inreturn(Fn("select",[vec;i]))(*
| CT_vector _, CT_constant i, _ -> Fn ("select", [smt_cval ctx vec; bvint !vector_index i])
| CT_vector _, index_ctyp, _ ->
Fn ("select", [smt_cval ctx vec; force_size ctx !vector_index (int_size ctx index_ctyp) (smt_cval ctx i)])
*)|_->builtin_type_error"vector_access"[vec;i](Someret_ctyp)letbuiltin_vector_subrangevecijret_ctyp=match(cval_ctypvec,cval_ctypi,cval_ctypj,ret_ctyp)with|CT_fbitsn,CT_constanti,CT_constantj,CT_fbits_->let*vec=smt_cvalvecinreturn(Extract(Big_int.to_inti,Big_int.to_intj,vec))|CT_lbits,CT_constanti,CT_constantj,CT_fbits_->let*vec=smt_cvalvecinreturn(Extract(Big_int.to_inti,Big_int.to_intj,Fn("contents",[vec])))(*
| CT_fbits n, i_ctyp, CT_constant j, CT_lbits when Big_int.equal j Big_int.zero ->
let i' = signed_size ~checked:false ctx ctx.lbits_index (int_size ctx i_ctyp) (smt_cval ctx i) in
let len = bvadd i' (bvint ctx.lbits_index (Big_int.of_int 1)) in
Fn ("Bits", [len; Fn ("bvand", [bvmask ctx len; unsigned_size ctx (lbits_size ctx) n (smt_cval ctx vec)])])
*)|bv_ctyp,i_ctyp,j_ctyp,ret_ctyp->let*vec=smt_cvalvecinletsz,vec=to_fbitsbv_ctypvecinlet*i'=bind(smt_cvali)(signed_size~into:sz~from:(int_sizei_ctyp))inlet*j'=bind(smt_cvalj)(signed_size~into:sz~from:(int_sizej_ctyp))inletlen=bvadd(bvaddi'(bvnegj'))(bvintsz(Big_int.of_int1))inletextracted=bvand(bvlshrvecj')(fbits_maskszlen)insmt_conversion~into:ret_ctyp~from:(CT_fbitssz)extractedletbuiltin_vector_updatevecixret_ctyp=match(cval_ctypvec,cval_ctypi,cval_ctypx,ret_ctyp)with|CT_fbitsn,CT_constanti,CT_bit,CT_fbitsmwhenn-1>Big_int.to_inti&&Big_int.to_inti>0->assert(n=m);let*bv=smt_cvalvecinlet*x=smt_cvalxinlettop=Extract(n-1,Big_int.to_inti+1,bv)inletbot=Extract(Big_int.to_inti-1,0,bv)inreturn(Fn("concat",[top;Fn("concat",[x;bot])]))|CT_fbitsn,CT_constanti,CT_bit,CT_fbitsmwhenn-1=Big_int.to_inti&&Big_int.to_inti>0->let*bv=smt_cvalvecinlet*x=smt_cvalxinletbot=Extract(Big_int.to_inti-1,0,bv)inreturn(Fn("concat",[x;bot]))|CT_fbitsn,CT_constanti,CT_bit,CT_fbitsmwhenn-1>Big_int.to_inti&&Big_int.to_inti=0->let*bv=smt_cvalvecinlet*x=smt_cvalxinlettop=Extract(n-1,1,bv)inreturn(Fn("concat",[top;x]))|CT_fbitsn,CT_constanti,CT_bit,CT_fbitsmwhenn-1=0&&Big_int.to_inti=0->smt_cvalx|CT_fbitsn,i_ctyp,CT_bit,CT_fbitsm->assert(n=m);let*bv=smt_cvalvecinlet*bit=smt_cvalxin(* Sail type system won't allow us to index out of range *)let*shift=bind(smt_cvali)(unsigned_size~checked:false~into:n~from:(int_sizei_ctyp))inletmask=bvnot(bvshl(ZeroExtend(n,n-1,bvone1))shift)inletshifted_bit=bvshl(ZeroExtend(n,n-1,bit))shiftinreturn(bvor(bvandmaskbv)shifted_bit)|CT_lbits,i_ctyp,CT_bit,CT_lbits->let*bv=smt_cvalvecinlet*bit=smt_cvalxin(* Sail type system won't allow us to index out of range *)let*shift=bind(smt_cvali)(unsigned_size~checked:false~into:lbits_size~from:(int_sizei_ctyp))inletmask=bvnot(bvshl(ZeroExtend(lbits_size,lbits_size-1,bvone1))shift)inletshifted_bit=bvshl(ZeroExtend(lbits_size,lbits_size-1,bit))shiftinletcontents=bvor(bvandmask(Fn("contents",[bv])))shifted_bitinreturn(Fn("Bits",[Fn("len",[bv]);contents]))|CT_fvector(len,ctyp),i_ctyp,_,CT_fvector(len_out,_)->assert(len=len_out);let*l=current_locationinletstore_fn=Primop_gen.fvector_storellenctypinlet*vec=smt_cvalvecinlet*x=smt_cvalxinlet*i=bind(smt_cvali)(unsigned_size~checked:false~into:(required_width(Big_int.of_int(len-1))-1)~from:(int_sizei_ctyp))inreturn(Store(Fixedlen,store_fn,vec,i,x))(*
| CT_vector _, CT_constant i, ctyp, CT_vector _ ->
Fn ("store", [smt_cval ctx vec; bvint !vector_index i; smt_cval ctx x])
| CT_vector _, index_ctyp, _, CT_vector _ ->
Fn
( "store",
[smt_cval ctx vec; force_size ctx !vector_index (int_size ctx index_ctyp) (smt_cval ctx i); smt_cval ctx x]
)
*)|_->builtin_type_error"vector_update"[vec;i;x](Someret_ctyp)letbuiltin_vector_update_subrangevecijxret_ctyp=match(cval_ctypvec,cval_ctypi,cval_ctypj,cval_ctypx,ret_ctyp)with|CT_fbitsn,CT_constanti,CT_constantj,CT_fbitssz,CT_fbitsmwhenn-1>Big_int.to_inti&&Big_int.to_intj>0->assert(n=m);let*vec=smt_cvalvecinlet*x=smt_cvalxinlettop=Extract(n-1,Big_int.to_inti+1,vec)inletbot=Extract(Big_int.to_intj-1,0,vec)inreturn(Fn("concat",[top;Fn("concat",[x;bot])]))|CT_fbitsn,CT_constanti,CT_constantj,CT_fbitssz,CT_fbitsmwhenn-1=Big_int.to_inti&&Big_int.to_intj>0->assert(n=m);let*vec=smt_cvalvecinlet*x=smt_cvalxinletbot=Extract(Big_int.to_intj-1,0,vec)inreturn(Fn("concat",[x;bot]))|CT_fbitsn,CT_constanti,CT_constantj,CT_fbitssz,CT_fbitsmwhenn-1>Big_int.to_inti&&Big_int.to_intj=0->assert(n=m);let*vec=smt_cvalvecinlet*x=smt_cvalxinlettop=Extract(n-1,Big_int.to_inti+1,vec)inreturn(Fn("concat",[top;x]))|CT_fbitsn,CT_constanti,CT_constantj,CT_fbitssz,CT_fbitsmwhenn-1=Big_int.to_inti&&Big_int.to_intj=0->smt_cvalx|CT_fbitsn,ctyp_i,ctyp_j,ctyp_x,CT_fbitsm->assert(n=m);let*vec=smt_cvalvecinlet*i'=bind(smt_cvali)(signed_size~into:n~from:(int_sizectyp_i))inlet*j'=bind(smt_cvalj)(signed_size~into:n~from:(int_sizectyp_j))inlet*x'=bind(smt_cvalx)(smt_conversion~into:(CT_fbitsn)~from:ctyp_x)inletlen=bvadd(bvaddi'(bvnegj'))(bvintn(Big_int.of_int1))inletmask=bvshl(fbits_masknlen)j'inreturn(bvor(bvandvec(bvnotmask))(bvand(bvshlx'j')mask))|bv_ctyp,ctyp_i,ctyp_j,ctyp_x,CT_lbits->let*sz,bv=fmap(to_fbitsbv_ctyp)(smt_cvalvec)inlet*i=bind(smt_cvali)(signed_size~into:sz~from:(int_sizectyp_i))inlet*j=bind(smt_cvalj)(signed_size~into:sz~from:(int_sizectyp_j))inlet*x=bind(smt_cvalx)(smt_conversion~into:(CT_fbitssz)~from:ctyp_x)inletlen=bvadd(bvaddi(bvnegj))(bvpintsz(Big_int.of_int1))inletmask=bvshl(fbits_maskszlen)jinletcontents=bvor(bvandbv(bvnotmask))(bvand(bvshlxj)mask)inlet*index=signed_size~into:lbits_index~from:szleninreturn(Fn("Bits",[index;contents]))|_->builtin_type_error"vector_update_subrange"[vec;i;j;x](Someret_ctyp)letbuiltin_get_slice_intv1v2v3ret_ctyp=match(cval_ctypv1,cval_ctypv2,cval_ctypv3,ret_ctyp)with|CT_constantlen,ctyp,CT_constantstart,CT_fbitsret_sz->letlen=Big_int.to_intleninletstart=Big_int.to_intstartinletin_sz=int_sizectypinlet*smt=ifin_sz<len+startthenbind(smt_cvalv2)(signed_size~into:(len+start)~from:in_sz)elsesmt_cvalv2inreturn(Extract(start+len-1,start,smt))|CT_lint,CT_lint,CT_constantstart,CT_lbitswhenBig_int.equalstartBig_int.zero->let*v1=smt_cvalv1inletlen=Extract(lbits_index-1,0,v1)inlet*contents=bind(smt_cvalv2)(unsigned_size~into:lbits_size~from:lint_size)inreturn(Fn("Bits",[len;bvand(bvmasklen)contents]))|ctyp1,ctyp2,ctyp3,ret_ctyp->let*smt1=smt_cvalv1inlet*len=signed_size~into:lbits_index~from:(int_sizectyp1)smt1inlet*smt2=bind(smt_cvalv2)(signed_size~into:lbits_size~from:(int_sizectyp2))inlet*smt3=bind(smt_cvalv3)(signed_size~into:lbits_size~from:(int_sizectyp3))inletresult=Fn("Bits",[len;bvand(bvmasklen)(bvlshrsmt2smt3)])insmt_conversion~into:ret_ctyp~from:CT_lbitsresultletbuiltin_pow2vret_ctyp=match(cval_ctypv,ret_ctyp)with|CT_constantn,_whenBig_int.greater_equalnBig_int.zero->return(bvint(int_sizeret_ctyp)(Big_int.pow_int_positive2(Big_int.to_intn)))|CT_lint,CT_lint->let*v=smt_cvalvin(* TODO: Check we haven't shifted too far *)return(bvshl(bvonelint_size)v)|_->builtin_type_error"pow2"[v](Someret_ctyp)(* Technically, there's no bvclz in SMTLIB, but we can't generate
anything nice, so leave it in case a backend like SystemVerilog
can do better *)letbuiltin_count_leading_zerosvret_ctyp=let*l=current_locationinmatchcval_ctypvwith|CT_fbitssz->letbvclz=Primop_gen.count_leading_zeroslszinlet*bv=smt_cvalvinunsigned_size~max_value:sz~into:(int_sizeret_ctyp)~from:sz(Fn(bvclz,[bv]))|CT_lbits->letbvclz=Primop_gen.count_leading_zerosllbits_sizeinlet*bv=smt_cvalvinletcontents_clz=Fn(bvclz,[Fn("contents",[bv])])inlet*len=unsigned_size~into:lbits_size~from:lbits_index(Fn("len",[bv]))inletlz=bvsubcontents_clz(bvsub(bvpintlbits_size(Big_int.of_intlbits_size))len)inunsigned_size~max_value:lbits_size~into:(int_sizeret_ctyp)~from:lbits_sizelz|_->builtin_type_error"count_leading_zeros"[v](Someret_ctyp)letarity_error=let*l=current_locationinraise(Reporting.unreachablel__POS__"Trying to generate primitive with incorrect number of arguments")letunary_primopf=Some(funargsret_ctyp->matchargswith[v]->fvret_ctyp|_->arity_error)letunary_primop_simplef=Some(funargs_->matchargswith[v]->fv|_->arity_error)letbinary_primopf=Some(funargsret_ctyp->matchargswith[v1;v2]->fv1v2ret_ctyp|_->arity_error)letbinary_primop_simplef=Some(funargs_->matchargswith[v1;v2]->fv1v2|_->arity_error)letternary_primopf=Some(funargsret_ctyp->matchargswith[v1;v2;v3]->fv1v2v3ret_ctyp|_->arity_error)letbuiltin=function|"eq_bit"->binary_primop_simple(funv1v2->let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inreturn(Fn("=",[smt1;smt2])))|"eq_bool"->binary_primop_simple(funv1v2->let*smt1=smt_cvalv1inlet*smt2=smt_cvalv2inreturn(Fn("=",[smt1;smt2])))|"eq_int"->binary_primop_simplebuiltin_eq_int|"not"->unary_primop_simple(funv->let*v=smt_cvalvinreturn(Fn("not",[v])))|"lt"->binary_primop_simplebuiltin_lt|"lteq"->binary_primop_simplebuiltin_lteq|"gt"->binary_primop_simplebuiltin_gt|"gteq"->binary_primop_simplebuiltin_gteq|"add_int"->binary_primopbuiltin_add_int|"sub_int"->binary_primopbuiltin_sub_int|"mult_int"->binary_primopbuiltin_mult_int|"neg_int"->unary_primopbuiltin_neg_int|"abs_int"->unary_primopbuiltin_abs_int|"max_int"->binary_primopbuiltin_max_int|"min_int"->binary_primopbuiltin_min_int|"pow2"->unary_primopbuiltin_pow2|"zeros"->unary_primopbuiltin_zeros|"ones"->unary_primopbuiltin_ones|"zero_extend"->binary_primopbuiltin_zero_extend|"sign_extend"->binary_primopbuiltin_sign_extend|"sail_signed"->unary_primopbuiltin_signed|"sail_unsigned"->unary_primopbuiltin_unsigned|"slice"->ternary_primopbuiltin_slice|"add_bits"->binary_primop(builtin_arith_bits"bvadd")|"add_bits_int"->binary_primop(builtin_arith_bits_int"bvadd")|"sub_bits"->binary_primop(builtin_arith_bits"bvsub")|"sub_bits_int"->binary_primop(builtin_arith_bits_int"bvsub")|"append"->binary_primopbuiltin_append|"get_slice_int"->ternary_primopbuiltin_get_slice_int|"eq_bits"->binary_primop_simplebuiltin_eq_bits|"neq_bits"->binary_primop_simplebuiltin_neq_bits|"not_bits"->unary_primopbuiltin_not_bits|"sail_truncate"->binary_primopbuiltin_sail_truncate|"sail_truncateLSB"->binary_primopbuiltin_sail_truncateLSB|"shiftl"->binary_primop(builtin_shift"bvshl")|"shiftr"->binary_primop(builtin_shift"bvlshr")|"arith_shiftr"->binary_primop(builtin_shift"bvashr")|"and_bits"->binary_primop(builtin_bitwise"bvand")|"or_bits"->binary_primop(builtin_bitwise"bvor")|"xor_bits"->binary_primop(builtin_bitwise"bvxor")|"vector_access"->binary_primopbuiltin_vector_access|"vector_subrange"->ternary_primopbuiltin_vector_subrange|"vector_update"->ternary_primopbuiltin_vector_update|"vector_update_subrange"->Some(funargsret_ctyp->matchargswith[v1;v2;v3;v4]->builtin_vector_update_subrangev1v2v3v4ret_ctyp|_->arity_error)|"length"->unary_primopbuiltin_length|"replicate_bits"->binary_primopbuiltin_replicate_bits|"count_leading_zeros"->unary_primopbuiltin_count_leading_zeros|"print_bits"->binary_primop_simple(funstrbv->let*l=current_locationinletop=Primop_gen.print_bitsl(cval_ctypbv)inlet*str=smt_cvalstrinlet*bv=smt_cvalbvinreturn(Fn(op,[str;bv])))|"string_of_bits"->unary_primop_simple(funbv->let*l=current_locationinletop=Primop_gen.string_of_bitsl(cval_ctypbv)inlet*bv=smt_cvalbvinreturn(Fn(op,[bv])))|"dec_str"->unary_primop_simple(funbv->let*l=current_locationinletop=Primop_gen.dec_strl(cval_ctypbv)inlet*bv=smt_cvalbvinreturn(Fn(op,[bv])))|"hex_str"->unary_primop_simple(funbv->let*l=current_locationinletop=Primop_gen.hex_strl(cval_ctypbv)inlet*bv=smt_cvalbvinreturn(Fn(op,[bv])))|"hex_str_upper"->unary_primop_simple(funbv->let*l=current_locationinletop=Primop_gen.hex_str_upperl(cval_ctypbv)inlet*bv=smt_cvalbvinreturn(Fn(op,[bv])))|"sail_assert"->binary_primop_simple(funbmsg->let*b=smt_cvalbinlet*msg=smt_cvalmsginreturn(Fn("sail_assert",[b;msg])))|"reg_deref"->unary_primop_simple(funreg_ref->matchcval_ctypreg_refwith|CT_refctyp->let*reg_ref=smt_cvalreg_refinletop="sail_reg_deref_"^Util.zencode_string(string_of_ctypctyp)inreturn(Fn(op,[reg_ref]))|_->let*l=current_locationinReporting.unreachablel__POS__"reg_deref given non register reference")|"sail_cons"->binary_primop_simple(funxxs->let*x=smt_cvalxinlet*xs=smt_cvalxsinreturn(Fn("cons",[x;xs])))|"eq_anything"->binary_primop_simple(funab->let*a=smt_cvalainlet*b=smt_cvalbinreturn(Fn("=",[a;b])))|_->Noneend