123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199(**************************************************************************)(* 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). *)(* *)(**************************************************************************)(** Concrete interpreter using OCaml boolean and [Z.t] for values. *)(** The interpreter values can be:
- [{true, false, empty}] for booleans;
- any [Z.t] or [empty] for integers;
- the set of bitvectors (represented by [Z.t] + empty).
Empty is not an error, just a special value representing the absence of value.
But, considering that whenever an argument is empty, the result is
empty, we can build an interpreter by focusing on the non-empty
values, and just return an exception for the (infrequent) empty cases. *)exceptionEmptymoduleIn_bits=Units.In_bitsmoduleTypes=structtypeboolean=booltypeinteger=Z.ttypebitvector=Z.t(* Should be positive, and only the |size| least significant bits
can be 1. (Note: even though the signed representation should
unbox more with Zarith). *)endmoduleBoolean_Interp:Operator_sig.BOOLEAN_FORWARDwithmoduleArity:=Operator_sig.Forward_Arityandtypeboolean=bool=structincludeTypesletfalse_=falselettrue_=truelet(||)=(||)let(&&)=(&&)letnot=notendmoduleBitvector_Interp:Operator_sig.BITVECTOR_FORWARDwithmoduleArity:=Operator_sig.Forward_Arityandtypeboolean=boolandtypebitvector=Z.t=structincludeTypesletbofbool~size:_=function|true->Z.one|false->Z.zeroletbiconst~sizex=Z.extractx0(In_bits.to_intsize)letbsext~size~oldsizex=letsize=In_bits.to_intsizeinletoldsize=In_bits.to_intoldsizeinZ.extract(Z.signed_extractx0oldsize)0size;;letbuext~size:_~oldsize:_x=x;;letbxor~size:_=Z.(lxor)letband~size:_=Z.(land)letbor~size:_=Z.(lor)letbiule~size:_=Z.leqletbeq~size:_=Z.equalletbisle~sizeab=letsize=In_bits.to_intsizeinleta=Z.signed_extracta0sizeinletb=Z.signed_extractb0sizeinZ.leqab;;letbshl~size~flagsxy=letsize=In_bits.to_intsizeinletFlags.Bshl.{nsw;nuw}=Flags.Bshl.unpackflagsinletyi=Z.to_intyinletres=(Z.shift_leftxyi)inifnuw&&Z.(geq)res(Z.shift_leftZ.onesize)thenraiseEmptyelseifnswthen(* The shifted out bits must be the same than the msb. *)letshifted_out_and_msb=Z.signed_extractres(size-1)(yi+1)inifZ.equalshifted_out_and_msbZ.zero||Z.equalshifted_out_and_msbZ.minus_onethen()elseraiseEmptyelse();Z.extractres0size;;letblshr~size:_xy=Z.shift_rightx(Z.to_inty);;letbashr~sizexy=letsize=In_bits.to_intsizeinZ.extract(Z.shift_right(Z.signed_extractx0size)(Z.to_inty))0size;;;;letbconcat~size1:_~size2ab=letsize2=In_bits.to_intsize2inZ.(lor)(Z.shift_leftasize2)b;;letbextract~size~index~oldsize:_x=Z.extractx(In_bits.to_intindex)(In_bits.to_intsize);;letsigned_overflow~sizex=letsize=In_bits.to_intsizeinZ.(geq)x(Z.shift_leftZ.one(size-1))||Z.(lt)x@@Z.neg(Z.shift_leftZ.one(size-1));;letunsigned_overflow~sizex=letsize=In_bits.to_intsizeinZ.(geq)x(Z.shift_leftZ.onesize);;letbiadd~size~flagsab=letFlags.Bisub.{nsw;nuw;nusw}=Flags.Biadd.unpackflagsinletres=Z.(+)abinifnuw&&unsigned_overflow~sizeresthenraiseEmptyelseifnusw&&letb=Z.signed_extractb0(size:>int)inletunsigned_res=Z.(+)abinunsigned_overflow~sizeunsigned_resthenraiseEmptyelseifnsw&&leta=Z.signed_extracta0(size:>int)inletb=Z.signed_extractb0(size:>int)inletsigned_res=Z.(+)abinsigned_overflow~sizesigned_resthenraiseEmptyelseZ.extractres0(size:>int);;letbisub~size~flagsab=letFlags.Bisub.{nsw;nuw;nusw}=Flags.Bisub.unpackflagsinletres=Z.(-)abinifnuw&&unsigned_overflow~sizeresthenraiseEmptyelseifnusw&&letb=Z.signed_extractb0(size:>int)inletunsigned_res=Z.(-)abinunsigned_overflow~sizeunsigned_resthenraiseEmptyelseifnsw&&leta=Z.signed_extracta0(size:>int)inletb=Z.signed_extractb0(size:>int)inletsigned_res=Z.(-)abinsigned_overflow~sizesigned_resthenraiseEmptyelseZ.extractres0(size:>int);;letbimul~size~flagsab=letab=Z.(*)abinletFlags.Bimul.{nsw;nuw}=Flags.Bimul.unpackflagsinifnuw&&unsigned_overflow~sizeabthenraiseEmptyelseifnsw&&letsa=Z.signed_extracta0(size:>int)inletsb=Z.signed_extractb0(size:>int)inletsab=Z.(*)sasbinsigned_overflow~sizesabthenraiseEmptyelseZ.extractab0(size:>int);;;;letbiudiv~size:_ab=ifZ.equalbZ.zerothenraiseEmptyelseZ.divabletbiumod~size:_ab=ifZ.equalbZ.zerothenraiseEmptyelseZ.remabletbisdiv~sizeab=letsize=In_bits.to_intsizeinifZ.equalbZ.zerothenraiseEmptyelseZ.extract(Z.div(Z.signed_extracta0size)(Z.signed_extractb0size))0sizeletbismod~sizeab=letsize=In_bits.to_intsizeinifZ.equalbZ.zerothenraiseEmptyelseZ.extract(Z.rem(Z.signed_extracta0size)(Z.signed_extractb0size))0sizeend