123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202typet={value:Z.t;width:int}letmaskwidth=Z.pred(Z.shift_leftZ.onewidth)letmakevm=letmasked_value=Z.logandv(maskm)in{value=masked_value;width=m}letview{value;_}=valueletnumbits{width;_}=widthletof_int8v=(* TODO: add a check on v to make sure it is not too big ? *)make(Z.of_intv)8letof_int32v=make(Z.of_int32v)32letof_int64v=make(Z.of_int64v)64letequalab=Z.equala.valueb.value&&a.width=b.widthleteqzv=Z.equalZ.zerov.valueleteq_onev=Z.equalZ.onev.valueletcompareab=Z.comparea.valueb.valueletmsbbv=Z.testbitbv.value(bv.width-1)letto_signedbv=letmsb=msbbvinifmsbthenZ.subbv.value(Z.shift_leftZ.onebv.width)elsebv.valueletto_int32v=ifnumbitsv<=32thenZ.to_int32(to_signedv)elseFmt.failwith"call to Smtml.Bitvector.to_int32 on a bitvector of size %d"v.widthletto_int64v=ifnumbitsv<=64thenZ.to_int64(to_signedv)elseFmt.failwith"call to Smtml.Bitvector.to_int32 on a bitvector of size %d"v.width(** Bitvector pretty printer. By default it prints signed bitvectors. *)letppfmtbv=letvalue=to_signedbvinZ.pp_printfmtvalue(* Unop *)letnegbv=make(Z.negbv.value)bv.widthletlognota=make(Z.lognota.value)a.widthletclzbv=letreccount_zerosi=ifi>=bv.width||Z.testbitbv.value(bv.width-1-i)thenielsecount_zeros(i+1)inmake(Z.of_int@@count_zeros0)bv.widthletctzbv=letreccount_zerosi=ifi>=bv.width||Z.testbitbv.valueithenielsecount_zeros(i+1)inmake(Z.of_int@@count_zeros0)bv.widthletpopcntbv=make(Z.of_int@@Z.popcountbv.value)bv.width(* Binop *)letaddab=assert(a.width=b.width);make(Z.adda.valueb.value)a.widthletsubab=assert(a.width=b.width);make(Z.suba.valueb.value)a.widthletmulab=assert(a.width=b.width);make(Z.mula.valueb.value)a.widthletdivab=assert(a.width=b.width);ifZ.equalb.valueZ.zerothenraiseDivision_by_zero;make(Z.div(to_signeda)(to_signedb))a.widthletdiv_uab=assert(a.width=b.width);ifZ.equalb.valueZ.zerothenraiseDivision_by_zero;make(Z.diva.valueb.value)a.widthletlogandab=assert(a.width=b.width);make(Z.loganda.valueb.value)a.widthletlogorab=assert(a.width=b.width);make(Z.logora.valueb.value)a.widthletlogxorab=assert(a.width=b.width);make(Z.logxora.valueb.value)a.widthletnormalize_shift_amountnwidth=(* FIXME: only works for widths that are powers of 2. *)assert(width>0&&widthland(width-1)=0);Z.to_int@@Z.logandn(Z.of_int(width-1))letshlan=letn=normalize_shift_amount(viewn)(numbitsa)inmake(Z.shift_lefta.valuen)a.widthletashran=letn=normalize_shift_amount(viewn)(numbitsa)inletsigned_value=to_signedainmake(Z.shift_rightsigned_valuen)a.widthletlshran=letn=normalize_shift_amount(viewn)(numbitsa)inmake(Z.shift_right_trunca.valuen)a.widthletremab=assert(a.width=b.width);ifZ.equalb.valueZ.zerothenraiseDivision_by_zero;make(Z.rem(to_signeda)(to_signedb))a.widthletrem_uab=assert(a.width=b.width);ifZ.equalb.valueZ.zerothenraiseDivision_by_zero;make(Z.rema.valueb.value)a.widthletrotate_leftbvn=letn=normalize_shift_amount(viewn)(numbitsbv)inletleft_part=Z.shift_leftbv.valueninletright_part=Z.shift_rightbv.value(bv.width-n)inletrotated=Z.logorleft_partright_partinmakerotatedbv.widthletrotate_rightbvn=letn=normalize_shift_amount(viewn)(numbitsbv)inletright_part=Z.shift_rightbv.valueninletleft_part=Z.shift_leftbv.value(bv.width-n)inletrotated=Z.logorleft_partright_partinmakerotatedbv.width(* Relop *)letlt_uab=Z.lta.valueb.valueletgt_uab=Z.gta.valueb.valueletle_uab=Z.leqa.valueb.valueletge_uab=Z.geqa.valueb.valueletltab=Z.lt(to_signeda)(to_signedb)letgtab=Z.gt(to_signeda)(to_signedb)letleab=Z.leq(to_signeda)(to_signedb)letgeab=Z.geq(to_signeda)(to_signedb)(* Extract and concat *)letconcatab=letnew_width=a.width+b.widthinletshifted=Z.shift_lefta.valueb.widthinletcombined=Z.logorshiftedb.valueinmakecombinednew_widthletextractbv~high~low=assert(high<bv.width&&low>=0&&low<=high);letwidth=high-low+1inletshifted=Z.shift_rightbv.valuelowinletextracted=Z.logandshifted(maskwidth)inmakeextractedwidth(* Cvtop *)letzero_extendwidthbv=letnew_width=bv.width+widthinmakebv.valuenew_widthletsign_extendwidthbv=letnew_width=bv.width+widthinletmsb=msbbvinletsign_mask=ifmsbthenletshift_amount=bv.widthinZ.shift_left(maskwidth)shift_amountelseZ.zeroinletextended=Z.logorbv.valuesign_maskinmakeextendednew_widthletto_stringbv=Fmt.str"%a"ppbvletto_jsonbv=`String(to_stringbv)