123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188(**************************************************************************)(* *)(* OCaml *)(* *)(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)(* *)(* Copyright 1996 Institut National de Recherche en Informatique et *)(* en Automatique. *)(* *)(* All rights reserved. This file is distributed under the terms of *)(* the GNU Lesser General Public License version 2.1, with the *)(* special exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)(* Description of primitive functions *)openMiscopenParsetreemoduleString=Misc.Stdlib.Stringtypeunboxed_or_untagged_integer=|Unboxed_int64|Unboxed_nativeint|Unboxed_int32|Untagged_int16|Untagged_int8|Untagged_inttypeunboxed_float=Unboxed_float64|Unboxed_float32typeunboxed_vector=Unboxed_vec128|Unboxed_vec256|Unboxed_vec512typeboxed_integer=Boxed_int64|Boxed_nativeint|Boxed_int32typeboxed_float=Boxed_float64|Boxed_float32typeboxed_vector=Boxed_vec128|Boxed_vec256|Boxed_vec512typenative_repr=|Repr_poly|Same_as_ocaml_reprofJkind_types.Sort.Const.t|Unboxed_floatofboxed_float|Unboxed_vectorofboxed_vector|Unboxed_or_untagged_integerofunboxed_or_untagged_integer|Unpacked_productofJkind_types.Sort.Const.ttypeeffects=No_effects|Only_generative_effects|Arbitrary_effectstypecoeffects=No_coeffects|Has_coeffectstypemode=|Prim_local|Prim_global|Prim_polytype'reprdescription_gen={prim_name:string;(* Name of primitive or C function *)prim_arity:int;(* Number of arguments *)prim_alloc:bool;(* Does it allocates or raise? *)prim_c_builtin:bool;(* Is the compiler allowed to replace it? *)prim_effects:effects;prim_coeffects:coeffects;prim_native_name:string;(* Name of C function for the nat. code gen. *)prim_native_repr_args:(mode*'repr)list;prim_native_repr_res:mode*'repr;prim_is_layout_poly:bool}typedescription=native_reprdescription_gen(* Is [[@@immediate]], so poly-compare can be used to de-dup errors. If a [loc]
is added, then errors will always be unique and de-duping will no longer be
necessary. *)typewrong_repr_error=|Product_arg|Expected_value_prim|Product_return|Unpacked_product_return|Repr_mismatch[@@immediate]letcompare_wrong_repr_error(a:wrong_repr_error)(b:wrong_repr_error)=Stdlib.compareabtypeerror=|Old_style_float_with_native_repr_attribute|Old_style_float_with_non_value|Old_style_noalloc_with_noalloc_attribute|No_native_primitive_with_repr_attribute|No_native_primitive_with_non_value|Inconsistent_attributes_for_effects|Inconsistent_noalloc_attributes_for_effects|Invalid_representation_polymorphic_attribute|Invalid_native_repr_for_primitiveof{prim_name:string;errors:wrong_repr_errorlist}exceptionErrorofLocation.t*errortypevalue_check=Bad_attribute|Bad_layout|Ok_valueletcheck_ocaml_value=function|_,Same_as_ocaml_repr(BaseScannable)->Ok_value|_,Same_as_ocaml_repr_|_,Repr_poly->Bad_layout|_,Unboxed_float_|_,Unboxed_vector_|_,Unboxed_or_untagged_integer_|_,Unpacked_product_->Bad_attributeletis_builtin_prim_namename=String.lengthname>0&&name.[0]='%'letrecmake_prim_repr_argsarityx=ifarity=0then[]elsex::make_prim_repr_args(arity-1)xletmake~name~alloc~c_builtin~effects~coeffects~native_name~native_repr_args~native_repr_res~is_layout_poly={prim_name=name;prim_arity=List.lengthnative_repr_args;prim_alloc=alloc;prim_c_builtin=c_builtin;prim_effects=effects;prim_coeffects=coeffects;prim_native_name=native_name;prim_native_repr_args=native_repr_args;prim_native_repr_res=native_repr_res;prim_is_layout_poly=is_layout_poly}letparse_declarationvaldecl~native_repr_args~native_repr_res~is_layout_poly=letarity=List.lengthnative_repr_argsinletname,native_name,old_style_noalloc,old_style_float=matchvaldecl.pval_primwith|name::"noalloc"::name2::"float"::_->(name,name2,true,true)|name::"noalloc"::name2::_->(name,name2,true,false)|name::name2::"float"::_->(name,name2,false,true)|name::"noalloc"::_->(name,"",true,false)|name::name2::_->(name,name2,false,false)|name::_->(name,"",false,false)|[]->fatal_error"Primitive.parse_declaration"inletnoalloc_attribute=Attr_helper.has_no_payload_attribute"noalloc"valdecl.pval_attributesinletbuiltin_attribute=Attr_helper.has_no_payload_attribute"builtin"valdecl.pval_attributesinletno_effects_attribute=Attr_helper.has_no_payload_attribute"no_effects"valdecl.pval_attributesinletonly_generative_effects_attribute=Attr_helper.has_no_payload_attribute"only_generative_effects"valdecl.pval_attributesinletis_builtin_prim=is_builtin_prim_namenameinletprim_is_layout_poly=matchis_builtin_prim,is_layout_polywith|false,true->raise(Error(valdecl.pval_loc,Invalid_representation_polymorphic_attribute))|_,b->binifno_effects_attribute&&only_generative_effects_attributethenraise(Error(valdecl.pval_loc,Inconsistent_attributes_for_effects));leteffects=ifno_effects_attributethenNo_effectselseifonly_generative_effects_attributethenOnly_generative_effectselseArbitrary_effectsinletno_coeffects_attribute=Attr_helper.has_no_payload_attribute"no_coeffects"valdecl.pval_attributesinletcoeffects=ifno_coeffects_attributethenNo_coeffectselseHas_coeffectsinifold_style_floatthenList.iter(funrepr->matchcheck_ocaml_valuereprwith|Ok_value->()|Bad_attribute->raise(Error(valdecl.pval_loc,Old_style_float_with_native_repr_attribute))|Bad_layout->raise(Error(valdecl.pval_loc,Old_style_float_with_non_value)))(native_repr_res::native_repr_args);ifold_style_noalloc&&noalloc_attributethenraise(Error(valdecl.pval_loc,Old_style_noalloc_with_noalloc_attribute));(* The compiler used to assume "noalloc" with "float", we just make this
explicit now (GPR#167): *)letold_style_noalloc=old_style_noalloc||old_style_floatinifold_style_floatthenLocation.deprecatedvaldecl.pval_loc"[@@unboxed] + [@@noalloc] should be used\n\
instead of \"float\""elseifold_style_noallocthenLocation.deprecatedvaldecl.pval_loc"[@@noalloc] should be used instead of \"noalloc\"";ifnative_name=""thenList.iter(funrepr->matchcheck_ocaml_valuereprwith|Ok_value->()|Bad_attribute->raise(Error(valdecl.pval_loc,No_native_primitive_with_repr_attribute))|Bad_layout->(* Built-in primitives don't need a native version. *)ifnotis_builtin_primthenraise(Error(valdecl.pval_loc,No_native_primitive_with_non_value)))(native_repr_res::native_repr_args);letnoalloc=old_style_noalloc||noalloc_attributeinifnoalloc&&only_generative_effects_attributethenraise(Error(valdecl.pval_loc,Inconsistent_noalloc_attributes_for_effects));letnative_repr_args,native_repr_res=ifold_style_floatthen(make_prim_repr_argsarity(Prim_global,Unboxed_floatBoxed_float64),(Prim_global,Unboxed_floatBoxed_float64))else(native_repr_args,native_repr_res)in{prim_name=name;prim_arity=arity;prim_alloc=notnoalloc;prim_c_builtin=builtin_attribute;prim_effects=effects;prim_coeffects=coeffects;prim_native_name=native_name;prim_native_repr_args=native_repr_args;prim_native_repr_res=native_repr_res;prim_is_layout_poly}openOutcometreeletadd_attribute_listtyattrs=List.fold_left(funtyattr->Otyp_attribute(ty,attr))tyattrsletrecadd_native_repr_attributestyattrs=matchty,attrswith(* Otyp_poly and Otyp_newlayout case might have been added in e.g.
tree_of_value_description *)|Otyp_poly(vars,ty),_->Otyp_poly(vars,add_native_repr_attributestyattrs)|Otyp_newlayout(vars,ty),_->Otyp_newlayout(vars,add_native_repr_attributestyattrs)|Otyp_arrow(label,am,a,Otyp_ret(rm,r)),attr_l::rest->letr=add_native_repr_attributesrrestinleta=add_attribute_listaattr_linOtyp_arrow(label,am,a,Otyp_ret(rm,r))|_,[attr_l]->add_attribute_listtyattr_l|_->assert(List.for_all(funx->x=[])attrs);tyletoattr_unboxed={oattr_name="unboxed"}letoattr_untagged={oattr_name="untagged"}letoattr_unpacked={oattr_name="unpacked"}letoattr_noalloc={oattr_name="noalloc"}letoattr_builtin={oattr_name="builtin"}letoattr_no_effects={oattr_name="no_effects"}letoattr_only_generative_effects={oattr_name="only_generative_effects"}letoattr_no_coeffects={oattr_name="no_coeffects"}letoattr_local_opt={oattr_name="local_opt"}letoattr_layout_poly={oattr_name="layout_poly"}letprintposig_val_decl=letprims=ifp.prim_native_name<>""then[p.prim_name;p.prim_native_name]else[p.prim_name]inletfor_allf=List.for_allfp.prim_native_repr_args&&fp.prim_native_repr_resinletneeds_unboxed_attribute=function|_,Same_as_ocaml_repr(BaseScannable)|_,Repr_poly|_,Unpacked_product_|_,Unboxed_or_untagged_integer(Untagged_int|Untagged_int8|Untagged_int16)->false|_,Unboxed_float_|_,Unboxed_vector_|_,Unboxed_or_untagged_integer(Unboxed_int64|Unboxed_int32|Unboxed_nativeint)->true|_,Same_as_ocaml_repr(BaseVoid)->false(* The [@unboxed] attribute is not supported on void in our compiler
or the upstream compiler. *)|_,Same_as_ocaml_repr_->(* We require [@unboxed] for non-value types in upstream-compatible code,
but treat it as optional otherwise. We thus print the [@unboxed]
attribute only in the case it's required and leave it out when it's
not. That's why we call [erasable_extensions_only] here. *)Language_extension.erasable_extensions_only()inletis_untagged=function|_,Unboxed_or_untagged_integer(Untagged_int8|Untagged_int16)->Language_extension.erasable_extensions_only()|_,Unboxed_or_untagged_integer(Untagged_int)->true|_,Same_as_ocaml_repr_|_,Unboxed_float_|_,Unboxed_vector_|_,Unboxed_or_untagged_integer(Unboxed_int64|Unboxed_int32|Unboxed_nativeint)|_,Unpacked_product_|_,Repr_poly->falseinletall_unboxed=for_allneeds_unboxed_attributeinletall_untagged=for_allis_untaggedinletattrs=ifp.prim_allocthen[]else[oattr_noalloc]inletattrs=ifp.prim_c_builtinthenoattr_builtin::attrselseattrsinletattrs=matchp.prim_effectswith|No_effects->oattr_no_effects::attrs|Only_generative_effects->oattr_only_generative_effects::attrs|Arbitrary_effects->attrsinletattrs=matchp.prim_coeffectswith|No_coeffects->oattr_no_coeffects::attrs|Has_coeffects->attrsinletattrs=ifall_unboxedthenoattr_unboxed::attrselseifall_untaggedthenoattr_untagged::attrselseattrsinletattrs=ifp.prim_is_layout_polythenoattr_layout_poly::attrselseattrsinletattrs_of_mode_and_repr(m,repr)=(matchmwith|Prim_local|Prim_global->[]|Prim_poly->[oattr_local_opt])@(matchreprwith|Same_as_ocaml_repr(BaseScannable)|Repr_poly->[]|Unboxed_float_|Unboxed_vector_|Unboxed_or_untagged_integer(Unboxed_int32|Unboxed_int64|Unboxed_nativeint)->ifall_unboxedthen[]else[oattr_unboxed]|Unboxed_or_untagged_integer(Untagged_int|Untagged_int8|Untagged_int16)->ifall_untaggedthen[]else[oattr_untagged]|Unpacked_product_->[oattr_unpacked]|Same_as_ocaml_repr_->ifall_unboxed||not(needs_unboxed_attribute(m,repr))then[]else[oattr_unboxed])inlettype_attrs=List.mapattrs_of_mode_and_reprp.prim_native_repr_args@[attrs_of_mode_and_reprp.prim_native_repr_res]in{osig_val_declwithoval_prims=prims;oval_type=add_native_repr_attributesosig_val_decl.oval_typetype_attrs;oval_attributes=attrs}letnative_namep=ifp.prim_native_name<>""thenp.prim_native_nameelsep.prim_nameletbyte_namep=p.prim_nameletunboxed_or_untagged_integer=function|Boxed_int32->Unboxed_int32|Boxed_nativeint->Unboxed_nativeint|Boxed_int64->Unboxed_int64letunboxed_float=function|Boxed_float32->Unboxed_float32|Boxed_float64->Unboxed_float64letunboxed_vector=function|Boxed_vec128->Unboxed_vec128|Boxed_vec256->Unboxed_vec256|Boxed_vec512->Unboxed_vec512(* Since these are just constant constructors, we can just use polymorphic equality and
comparison at no performance loss. We still match on the variants to prove here that
they are all constant constructors. *)letequal_unboxed_or_untagged_integer((Unboxed_int64|Unboxed_nativeint|Unboxed_int32|Untagged_int16|Untagged_int8|Untagged_int)asi1)i2=i1=i2letequal_unboxed_float((Unboxed_float32|Unboxed_float64)asf1)f2=f1=f2letcompare_unboxed_float((Unboxed_float32|Unboxed_float64)asf1)f2=Stdlib.comparef1f2letequal_unboxed_vector((Unboxed_vec128|Unboxed_vec256|Unboxed_vec512)asv1)v2=v1=v2letcompare_unboxed_vector((Unboxed_vec128|Unboxed_vec256|Unboxed_vec512)asv1)v2=Stdlib.comparev1v2letequal_boxed_integerbi1bi2=equal_unboxed_or_untagged_integer(unboxed_or_untagged_integerbi1)(unboxed_or_untagged_integerbi2)letequal_boxed_floatbf1bf2=equal_unboxed_float(unboxed_floatbf1)(unboxed_floatbf2)letequal_boxed_vectorbv1bv2=equal_unboxed_vector(unboxed_vectorbv1)(unboxed_vectorbv2)letcompare_boxed_floatbf1bf2=compare_unboxed_float(unboxed_floatbf1)(unboxed_floatbf2)letcompare_boxed_vectorbv1bv2=compare_unboxed_vector(unboxed_vectorbv1)(unboxed_vectorbv2)letequal_unboxed_vector_sizev1v2=(* For the purposes of layouts/native representations,
vectors of the same width are equal. *)matchv1,v2with|Unboxed_vec128,Unboxed_vec128->true|Unboxed_vec256,Unboxed_vec256->true|Unboxed_vec512,Unboxed_vec512->true|(Unboxed_vec128|Unboxed_vec256|Unboxed_vec512),_->falseletequal_native_reprnr1nr2=matchnr1,nr2with|Repr_poly,Repr_poly->true|Repr_poly,(Unboxed_float_|Unboxed_or_untagged_integer_|Unboxed_vector_|Same_as_ocaml_repr_|Unpacked_product_)|(Unboxed_float_|Unboxed_or_untagged_integer_|Unboxed_vector_|Same_as_ocaml_repr_|Unpacked_product_),Repr_poly->false|Same_as_ocaml_reprs1,Same_as_ocaml_reprs2->Jkind_types.Sort.Const.equals1s2|Same_as_ocaml_repr_,(Unboxed_float_|Unboxed_or_untagged_integer_|Unboxed_vector_|Unpacked_product_)->false|Unboxed_floatf1,Unboxed_floatf2->equal_boxed_floatf1f2|Unboxed_float_,(Same_as_ocaml_repr_|Unboxed_or_untagged_integer_|Unboxed_vector_|Unpacked_product_)->false|Unboxed_vectorvi1,Unboxed_vectorvi2->equal_unboxed_vector_size(unboxed_vectorvi1)(unboxed_vectorvi2)|Unboxed_vector_,(Same_as_ocaml_repr_|Unboxed_float_|Unboxed_or_untagged_integer_|Unpacked_product_)->false|Unboxed_or_untagged_integerbi1,Unboxed_or_untagged_integerbi2->equal_unboxed_or_untagged_integerbi1bi2|Unboxed_or_untagged_integer_,(Same_as_ocaml_repr_|Unboxed_float_|Unboxed_vector_|Unpacked_product_)->false|Unpacked_products1,Unpacked_products2->Jkind_types.Sort.Const.equals1s2|Unpacked_product_,(Same_as_ocaml_repr_|Unboxed_float_|Unboxed_vector_|Unboxed_or_untagged_integer_)->falseletequal_effectsef1ef2=matchef1,ef2with|No_effects,No_effects->true|No_effects,(Only_generative_effects|Arbitrary_effects)->false|Only_generative_effects,Only_generative_effects->true|Only_generative_effects,(No_effects|Arbitrary_effects)->false|Arbitrary_effects,Arbitrary_effects->true|Arbitrary_effects,(No_effects|Only_generative_effects)->falseletequal_coeffectscf1cf2=matchcf1,cf2with|No_coeffects,No_coeffects->true|No_coeffects,Has_coeffects->false|Has_coeffects,Has_coeffects->true|Has_coeffects,No_coeffects->falseletnative_name_is_externalp=letnat_name=native_namepinnat_name<>""&&nat_name.[0]<>'%'moduleRepr_check=structtyperesult=|Wrong_arity|Wrong_reprofwrong_repr_errorlist(* non-empty list *)|Successletargs_res_reprsprim=(prim.prim_native_repr_args@[prim.prim_native_repr_res])|>List.mapsndletisexpected_reprrepr:wrong_repr_errorlist=ifequal_native_reprexpected_reprreprthen[]else[Repr_mismatch]letany=fun_->[]letvalue_or_unboxed_or_untagged=function|Same_as_ocaml_repr(BaseScannable)|Unboxed_float_|Unboxed_or_untagged_integer_|Unboxed_vector_->true|Same_as_ocaml_repr_|Repr_poly|Unpacked_product_->falseletsort_is_product:Jkind_types.Sort.Const.t->bool=function|Product_->true|Base_->false|Univar_->Misc.fatal_error"sort_is_product: univar"|Genvar_->Misc.fatal_error"sort_is_product: genvar"letc_stub_arg_errors=function|Same_as_ocaml_reprs->ifsort_is_productsthen[Product_arg]else[]|Unboxed_float_|Unboxed_or_untagged_integer_|Unboxed_vector_|Unpacked_product_|Repr_poly->[]letc_stub_return_errors=function|Same_as_ocaml_repr(Base_)|Unboxed_float_|Unboxed_or_untagged_integer_|Unboxed_vector_|Repr_poly->[]|Unpacked_product_->[Unpacked_product_return]|Same_as_ocaml_repr(Product[s1;s2])->if(sort_is_products1)||(sort_is_products2)then[Product_return]else[]|Same_as_ocaml_repr(Product_)->[Product_return]|Same_as_ocaml_repr(Univar_)->Misc.fatal_error"c_stub_return_errors: univar"|Same_as_ocaml_repr(Genvar_)->Misc.fatal_error"c_stub_return_errors: genvar"(* [checks = [check_arg1; check_arg2; ..; check_argn; check_ret]], where for
each check, [check (repr : native_repr)] returns a [wrong_repr_error list].
If the returned list is empty, then the check succeeded. For example,
[check [any; is (Same_as_ocaml_repr C.scannable)] prim_desc] checks that
[prim_desc] accepts a single argument of any layout and returns a
scannable value. *)letcheckchecksprim=letreprs=args_res_reprspriminifList.lengthreprs<>List.lengthchecksthenWrong_arityelsebeginletrepr_errors=List.concat(List.map2(funfx->fx)checksreprs)inifList.is_emptyrepr_errorsthenSuccesselseWrong_reprrepr_errorsendletexactlyrequired=check(List.mapisrequired)letsame_arg_res_repr_with_arityarityprim=letrepr=sndprim.prim_native_repr_resinexactly(List.init(arity+1)(fun_->repr))primletno_non_value_reprprim=letarity=List.lengthprim.prim_native_repr_argsincheck(List.init(arity+1)(fun_repr->ifvalue_or_unboxed_or_untaggedreprthen[]else[Expected_value_prim]))primletcheck_c_stubprim=(* C externals are allowed to return a tuple, but may not take products as
arguments or return products with more than two elements. *)letarity=List.lengthprim.prim_native_repr_argsinletchecks=(List.initarity(fun_->c_stub_arg_errors))@[c_stub_return_errors]incheckchecksprimend(* Note: [any] here is not the same as jkind [any]. It means we allow any
[native_repr] for the corresponding argument or return. It's [Typedecl]'s
responsibility to check that types in externals are representable or marked
with [@layout_poly] (see [make_native_repr] and the note above
[error_if_containing_unexpected_jkind]). Here we have more speicific checks
for individual primitives. *)letprim_has_valid_reprs~locprim=letopenRepr_checkinletmoduleC=Jkind_types.Sort.Constinletcheck=(* Corresponds to [indexing_primitives] in [translprim.ml]. *)letstringlike_indexing_primitives=letwidths:(_*_*Jkind_types.Sort.Const.t)list=[("8","",C.scannable);("i8","",C.scannable);("16","",C.scannable);("i16","",C.scannable);("32","",C.scannable);("f32","",C.scannable);("64","",C.scannable);("a128","",C.scannable);("u128","",C.scannable);("a256","",C.scannable);("u256","",C.scannable);("a512","",C.scannable);("u512","",C.scannable);("8","#",C.bits8);("i8","#",C.bits8);("16","#",C.bits16);("i16","#",C.bits16);("32","#",C.bits32);("f32","#",C.float32);("64","#",C.bits64);("a128","#",C.vec128);("u128","#",C.vec128);("a256","#",C.vec256);("u256","#",C.vec256);("a512","#",C.vec512);("u512","#",C.vec512);]inletindices:(_*Jkind_types.Sort.Const.t)list=[("",C.scannable);("_indexed_by_nativeint#",C.word);("_indexed_by_int8#",C.bits8);("_indexed_by_int16#",C.bits16);("_indexed_by_int32#",C.bits32);("_indexed_by_int64#",C.bits64);]inletcombiners=[(Printf.sprintf"%%caml_%s_get%s%s%s%s",funindex_kindwidth_kind->[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprindex_kind;Same_as_ocaml_reprwidth_kind;]);(Printf.sprintf"%%caml_%s_set%s%s%s%s",funindex_kindwidth_kind->[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprindex_kind;Same_as_ocaml_reprwidth_kind;Same_as_ocaml_reprC.scannable;]);]in(let(let*)xf=List.concat_mapfxinlet*container=["bigstring";"bytes";"string"]inlet*safe_sigil=["";"u"]inlet*index_sigil,index_kind=indicesinlet*width_sigil,unboxed_sigil,width_kind=widthsinlet*combine_string,combine_repr=combinersinletstring=combine_stringcontainerwidth_sigilsafe_sigilunboxed_sigilindex_sigilinletreprs=combine_reprindex_kindwidth_kindin[(string,reprs)])|>List.to_seq|>funseq->String.Map.add_seqseqString.Map.emptyin(* Corresponds to [array_vec_primitives] in [translprim.ml]. *)letvector_array_indexing_primitives=letvector_sizes=[("128","",C.scannable);("128","#",C.vec128);("256","",C.scannable);("256","#",C.vec256);("512","",C.scannable);("512","#",C.vec512);]inletarray_types=["float_array";"floatarray";"unboxed_float_array";"unboxed_float32_array";"int_array";"unboxed_int64_array";"unboxed_int32_array";"untagged_int16_array";"untagged_int8_array";"unboxed_nativeint_array";]inletsafe_sigils=["";"u"]inletindices=[("",C.scannable);("_indexed_by_nativeint#",C.word);("_indexed_by_int8#",C.bits8);("_indexed_by_int16#",C.bits16);("_indexed_by_int32#",C.bits32);("_indexed_by_int64#",C.bits64);]inletcombiners=[(Printf.sprintf"%%caml_%s_get%s%s%s%s",funindex_kindvector_kind->[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprindex_kind;Same_as_ocaml_reprvector_kind;]);(Printf.sprintf"%%caml_%s_set%s%s%s%s",funindex_kindvector_kind->[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprindex_kind;Same_as_ocaml_reprvector_kind;Same_as_ocaml_reprC.scannable;]);]in(let(let*)xf=List.concat_mapfxinlet*array_type=array_typesinlet*safe_sigil=safe_sigilsinlet*size_str,unboxed_sigil,vector_kind=vector_sizesinlet*index_suffix,index_kind=indicesinlet*combine_string,combine_repr=combinersinletstring=combine_stringarray_typesize_strsafe_sigilunboxed_sigilindex_suffixinletreprs=combine_reprindex_kindvector_kindin[(string,reprs)])|>List.to_seq|>funseq->String.Map.add_seqseqString.Map.emptyinmatchprim.prim_namewith|"%identity"|"%opaque"|"%obj_magic"->same_arg_res_repr_with_arity1|"%ignore"->check[any;is(Same_as_ocaml_reprC.scannable)]|"%revapply"->check[any;is(Same_as_ocaml_reprC.scannable);any]|"%apply"->check[is(Same_as_ocaml_reprC.scannable);any;any](* This doesn't prevent
{|
external get : float# array -> int -> int32# =
"%array_safe_get"
|}
but the same is true for types:
{|
external get : float array -> int -> int32 =
"%array_safe_get"
|}
*)|"%array_safe_get"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.scannable);any]|"%array_safe_set"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.scannable);any;is(Same_as_ocaml_reprC.scannable)]|"%array_unsafe_get"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.scannable);any]|"%array_unsafe_set"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.scannable);any;is(Same_as_ocaml_reprC.scannable)]|"%array_safe_get_indexed_by_int64#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits64);any]|"%array_safe_set_indexed_by_int64#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits64);any;is(Same_as_ocaml_reprC.scannable)]|"%array_unsafe_get_indexed_by_int64#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits64);any]|"%array_unsafe_set_indexed_by_int64#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits64);any;is(Same_as_ocaml_reprC.scannable)]|"%array_safe_get_indexed_by_int32#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits32);any]|"%array_safe_set_indexed_by_int32#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits32);any;is(Same_as_ocaml_reprC.scannable)]|"%array_unsafe_get_indexed_by_int32#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits32);any]|"%array_unsafe_set_indexed_by_int32#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits32);any;is(Same_as_ocaml_reprC.scannable)]|"%array_safe_get_indexed_by_int16#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits16);any]|"%array_safe_set_indexed_by_int16#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits16);any;is(Same_as_ocaml_reprC.scannable)]|"%array_unsafe_get_indexed_by_int16#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits16);any]|"%array_unsafe_set_indexed_by_int16#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits16);any;is(Same_as_ocaml_reprC.scannable)]|"%array_safe_get_indexed_by_int8#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits8);any]|"%array_safe_set_indexed_by_int8#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits8);any;is(Same_as_ocaml_reprC.scannable)]|"%array_unsafe_get_indexed_by_int8#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits8);any]|"%array_unsafe_set_indexed_by_int8#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits8);any;is(Same_as_ocaml_reprC.scannable)]|"%array_safe_get_indexed_by_nativeint#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.word);any]|"%array_safe_set_indexed_by_nativeint#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.word);any;is(Same_as_ocaml_reprC.scannable)]|"%array_unsafe_get_indexed_by_nativeint#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.word);any]|"%array_unsafe_set_indexed_by_nativeint#"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.word);any;is(Same_as_ocaml_reprC.scannable)]|"%makearray_dynamic"->check[is(Same_as_ocaml_reprC.scannable);any;is(Same_as_ocaml_reprC.scannable);]|"%makearray_dynamic_uninit"->(* Restrictions on this primitive are checked in [Translprim] *)check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.scannable);]|"%array_element_size_in_bytes"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.scannable);]|"%peek"|"%poke"->(* Arities and layouts of these primitives are checked in [Translprim] *)fun_->Success|"%get_idx"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits64);any]|"%get_idx_imm"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits64);any]|"%set_idx"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits64);any;is(Same_as_ocaml_reprC.scannable);]|"%unsafe_array_idx"->check[is(Same_as_ocaml_reprC.scannable);is(Same_as_ocaml_reprC.bits64);]|"%unsafe_array_idx_indexed_by_int8#"->check[is(Same_as_ocaml_reprC.bits8);is(Same_as_ocaml_reprC.bits64);]|"%unsafe_array_idx_indexed_by_int16#"->check[is(Same_as_ocaml_reprC.bits16);is(Same_as_ocaml_reprC.bits64);]|"%unsafe_array_idx_indexed_by_int32#"->check[is(Same_as_ocaml_reprC.bits32);is(Same_as_ocaml_reprC.bits64);]|"%unsafe_array_idx_indexed_by_int64#"->check[is(Same_as_ocaml_reprC.bits64);is(Same_as_ocaml_reprC.bits64);]|"%unsafe_array_idx_indexed_by_nativeint#"->check[is(Same_as_ocaml_reprC.word);is(Same_as_ocaml_reprC.bits64);]|"%unsafe_get_ptr"->check[is(Same_as_ocaml_repr(C.Product[C.scannable;C.bits64]));any]|"%unsafe_get_ptr_imm"->check[is(Same_as_ocaml_repr(C.Product[C.scannable;C.bits64]));any]|"%unsafe_set_ptr"->check[is(Same_as_ocaml_repr(C.Product[C.scannable;C.bits64]));any;is(Same_as_ocaml_reprC.scannable);]|"%box_float"->exactly[Same_as_ocaml_reprC.float64;Same_as_ocaml_reprC.scannable]|"%unbox_float"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.float64]|"%box_float32"->exactly[Same_as_ocaml_reprC.float32;Same_as_ocaml_reprC.scannable]|"%unbox_float32"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.float32]|"%box_nativeint"->exactly[Same_as_ocaml_reprC.word;Same_as_ocaml_reprC.scannable]|"%unbox_nativeint"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.word]|"%domain_index"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.untagged_immediate]|"%tag_int"->exactly[Same_as_ocaml_reprC.untagged_immediate;Same_as_ocaml_reprC.scannable]|"%untag_int"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.untagged_immediate]|"%tag_int8"->exactly[Same_as_ocaml_reprC.bits8;Same_as_ocaml_reprC.scannable]|"%untag_int8"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.bits8]|"%tag_int16"->exactly[Same_as_ocaml_reprC.bits16;Same_as_ocaml_reprC.scannable]|"%untag_int16"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.bits16]|"%box_int32"->exactly[Same_as_ocaml_reprC.bits32;Same_as_ocaml_reprC.scannable]|"%unbox_int32"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.bits32]|"%box_int64"->exactly[Same_as_ocaml_reprC.bits64;Same_as_ocaml_reprC.scannable]|"%unbox_int64"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.bits64]|"%unbox_unit"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.void]|"%box_vec128"->exactly[Same_as_ocaml_reprC.vec128;Same_as_ocaml_reprC.scannable]|"%unbox_vec128"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.vec128]|"%box_vec256"->exactly[Same_as_ocaml_reprC.vec256;Same_as_ocaml_reprC.scannable]|"%unbox_vec256"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.vec256]|"%join_vec256"->exactly[Same_as_ocaml_reprC.vec128;Same_as_ocaml_reprC.vec128;Same_as_ocaml_reprC.vec256]|"%split_vec256"->exactly[Same_as_ocaml_reprC.vec256;Same_as_ocaml_repr(Product[C.vec128;C.vec128])]|"%box_vec512"->exactly[Same_as_ocaml_reprC.vec512;Same_as_ocaml_reprC.scannable]|"%unbox_vec512"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.vec512]|"%reinterpret_tagged_int63_as_unboxed_int64"->exactly[Same_as_ocaml_reprC.scannable;Same_as_ocaml_reprC.bits64]|"%reinterpret_unboxed_int64_as_tagged_int63"->exactly[Same_as_ocaml_reprC.bits64;Same_as_ocaml_reprC.scannable]|name->(matchString.Map.find_optnamestringlike_indexing_primitiveswith|Somereprs->exactlyreprs|None->matchString.Map.find_optnamevector_array_indexing_primitiveswith|Somereprs->exactlyreprs|None->letmoduleI=Scalar.OperationinmatchI.With_percent_prefix.of_stringnamewith|intrinsic->exactly(List.map(funsort->Same_as_ocaml_reprsort)(I.sortintrinsic))|exceptionNot_found->ifis_builtin_prim_namenamethenno_non_value_repr(* These can probably support non-value reprs if the
need arises:
{|
| "%send"
| "%sendself"
| "%sendcache"
|}
*)elsecheck_c_stub)inmatchcheckprimwith|Success->()|Wrong_arity->(* There's already an arity check in translprim that catches this. We will
defer to that logic. We are only checking the arity of some built-in
primitives here but not all, and it would be weird to raise different
errors dependent on the [prim_name]. *)()|Wrong_reprerrors->raise(Error(loc,Invalid_native_repr_for_primitive{prim_name=prim.prim_name;errors}))letprim_can_contain_layout_anyprim=matchprim.prim_namewith|"%array_length"|"%array_blit"|"%array_safe_get"|"%array_safe_set"|"%array_unsafe_get"|"%array_unsafe_set"|"%array_safe_get_indexed_by_int64#"|"%array_safe_set_indexed_by_int64#"|"%array_unsafe_get_indexed_by_int64#"|"%array_unsafe_set_indexed_by_int64#"|"%array_safe_get_indexed_by_int32#"|"%array_safe_set_indexed_by_int32#"|"%array_unsafe_get_indexed_by_int32#"|"%array_unsafe_set_indexed_by_int32#"|"%array_safe_get_indexed_by_nativeint#"|"%array_safe_set_indexed_by_nativeint#"|"%array_unsafe_get_indexed_by_nativeint#"|"%array_unsafe_set_indexed_by_nativeint#"->false|_->truemoduleStyle=Misc.Styleletreport_errorppferr=matcherrwith|Old_style_float_with_native_repr_attribute->Format_doc.fprintfppf"Cannot use %a in conjunction with %a/%a."Style.inline_code"float"Style.inline_code"[@unboxed]"Style.inline_code"[@untagged]"|Old_style_float_with_non_value->Format_doc.fprintfppf"Cannot use %a in conjunction with \
types of non-value layouts."Style.inline_code"float"|Old_style_noalloc_with_noalloc_attribute->Format_doc.fprintfppf"Cannot use %a in conjunction with %a."Style.inline_code"noalloc"Style.inline_code"[@@noalloc]"|No_native_primitive_with_repr_attribute->Format_doc.fprintfppf"@[The native code version of the primitive is mandatory@ \
when attributes %a or %a are present.@]"Style.inline_code"[@untagged]"Style.inline_code"[@unboxed]"|No_native_primitive_with_non_value->Format_doc.fprintfppf"@[The native code version of the primitive is mandatory@ \
for types with non-value layouts.@]"|Inconsistent_attributes_for_effects->Format_doc.fprintfppf"At most one of %a and %a can be specified."Style.inline_code"[@no_effects]"Style.inline_code"[@only_generative_effects]"|Inconsistent_noalloc_attributes_for_effects->Format_doc.fprintfppf"Cannot use %a in conjunction with %a."Style.inline_code"[@@no_generative_effects]"Style.inline_code"[@@noalloc]"|Invalid_representation_polymorphic_attribute->Format_doc.fprintfppf"Attribute %a can only be used \
on built-in primitives."Style.inline_code"[@layout_poly]"|Invalid_native_repr_for_primitive{prim_name;errors}->Format_doc.fprintfppf"The primitive [%s] is used in an invalid declaration.@ \
The declaration contains argument/return types with the@ \
wrong layout."prim_name;leterrors=List.sort_uniqcompare_wrong_repr_errorerrorsinList.iter(function|Product_arg->Format_doc.fprintfppf"@.@{<hint>Hint@}: @[<v>\
Types with product layouts in C stub arguments require the@ \
%a attribute.@]"Style.inline_code"[@unpacked]"|Expected_value_prim->Format_doc.fprintfppf"@.@{<hint>Hint@}: @[<v>\
This was expected to be a value-only primitive. You might've@ \
misspelled the primitive name.@]"|Product_return->Format_doc.fprintfppf"@.@{<hint>Hint@}: @[<v>\
Unboxed products in C stub returns must be a pair of non-products.@]"|Unpacked_product_return->Format_doc.fprintfppf"@.@{<hint>Hint@}: @[<v>\
The %a attribute is not allowed on C stub returns.@]"Style.inline_code"[@unpacked]"|Repr_mismatch->()(* The error message already says "wrong layout", so a hint here would
be redundant. *))errorslet()=Location.register_error_of_exn(function|Error(loc,err)->Some(Location.error_of_printer~locreport_errorerr)|_->None)