@@ -114,6 +114,24 @@ type loc_kind =
114114 | Loc_POS
115115 | Loc_FUNCTION
116116
117+ type atomic_kind =
118+ | Ref (* operation on an atomic reference (takes only a pointer) *)
119+ | Field (* operation on an atomic field (takes a pointer and an offset) *)
120+ | Loc (* operation on a first-class field (takes a (pointer, offset) pair *)
121+
122+ type atomic_op =
123+ | Load
124+ | Set
125+ | Exchange
126+ | Compare_exchange
127+ | Cas
128+ | Faa
129+ | Add
130+ | Sub
131+ | Lxor
132+ | Land
133+ | Lor
134+
117135type prim =
118136 | Primitive of Lambda .primitive * int
119137 | External of Lambda .external_call_description
@@ -134,6 +152,7 @@ type prim =
134152 | Poke of Lambda .peek_or_poke option
135153 (* For [Peek] and [Poke] the [option] is [None] until the primitive
136154 specialization code (below) has been run. *)
155+ | Atomic of atomic_op * atomic_kind
137156 | Unsupported of Lambda .primitive
138157
139158let units_with_used_primitives = Hashtbl. create 7
@@ -897,22 +916,26 @@ let lookup_primitive loc ~poly_mode ~poly_sort pos p =
897916 | "%unbox_vec128" -> Primitive (Punbox_vector Boxed_vec128 , 1 )
898917 | "%box_vec128" -> Primitive (Pbox_vector (Boxed_vec128 , mode), 1 )
899918 | "%get_header" -> Primitive (Pget_header mode, 1 )
900- | "%atomic_load" ->
901- Primitive ((Patomic_load {immediate_or_pointer= Pointer }), 1 )
902- | "%atomic_set" ->
903- Primitive (Patomic_set {immediate_or_pointer= Pointer }, 2 )
904- | "%atomic_exchange" ->
905- Primitive (Patomic_exchange {immediate_or_pointer= Pointer }, 2 )
906- | "%atomic_compare_exchange" ->
907- Primitive (Patomic_compare_exchange {immediate_or_pointer= Pointer }, 3 )
908- | "%atomic_cas" ->
909- Primitive (Patomic_compare_set {immediate_or_pointer= Pointer }, 3 )
910- | "%atomic_fetch_add" -> Primitive (Patomic_fetch_add , 2 )
911- | "%atomic_add" -> Primitive (Patomic_add , 2 )
912- | "%atomic_sub" -> Primitive (Patomic_sub , 2 )
913- | "%atomic_land" -> Primitive (Patomic_land , 2 )
914- | "%atomic_lor" -> Primitive (Patomic_lor , 2 )
915- | "%atomic_lxor" -> Primitive (Patomic_lxor , 2 )
919+ (* CR melse: field/loc variants of other primitives *)
920+ | "%atomic_load" -> Atomic (Load , Ref )
921+ | "%atomic_load_field" -> Atomic (Load , Field )
922+ | "%atomic_load_loc" -> Atomic (Load , Loc )
923+ | "%atomic_set" -> Atomic (Set , Ref )
924+ | "%atomic_exchange" -> Atomic (Exchange , Ref )
925+ | "%atomic_exchange_field" -> Atomic (Exchange , Field )
926+ | "%atomic_exchange_loc" -> Atomic (Exchange , Loc )
927+ | "%atomic_compare_exchange" -> Atomic (Compare_exchange , Ref )
928+ | "%atomic_cas" -> Atomic (Cas , Ref )
929+ | "%atomic_cas_field" -> Atomic (Cas , Field )
930+ | "%atomic_cas_loc" -> Atomic (Cas , Loc )
931+ | "%atomic_fetch_add" -> Atomic (Faa , Ref )
932+ | "%atomic_fetch_add_field" -> Atomic (Faa , Field )
933+ | "%atomic_fetch_add_loc" -> Atomic (Faa , Loc )
934+ | "%atomic_add" -> Atomic (Add , Ref )
935+ | "%atomic_sub" -> Atomic (Sub , Ref )
936+ | "%atomic_land" -> Atomic (Land , Ref )
937+ | "%atomic_lor" -> Atomic (Lor , Ref )
938+ | "%atomic_lxor" -> Atomic (Lxor , Ref )
916939 | "%runstack" ->
917940 if runtime5 then Primitive (Prunstack , 3 ) else Unsupported Prunstack
918941 | "%reperform" ->
@@ -1624,6 +1647,90 @@ let lambda_of_loc kind sloc =
16241647 ~include_zero_alloc: false sloc in
16251648 Lconst (Const_immstring scope_name)
16261649
1650+ let atomic_arity op (kind : atomic_kind ) =
1651+ let arity_of_op =
1652+ match op with
1653+ | Load -> 1
1654+ | Set -> 2
1655+ | Exchange -> 2
1656+ | Compare_exchange -> 3
1657+ | Cas -> 3
1658+ | Faa -> 2
1659+ | Add | Sub | Lxor | Land | Lor -> 2
1660+ in
1661+ let extra_kind_arity =
1662+ match kind with
1663+ | Ref | Loc -> 0
1664+ | Field -> 1
1665+ in
1666+ arity_of_op + extra_kind_arity
1667+
1668+ let lambda_of_atomic prim_name loc op (kind : atomic_kind ) args =
1669+ if List. length args <> atomic_arity op kind then
1670+ raise (Error (to_location loc, Wrong_arity_builtin_primitive prim_name)) ;
1671+ let split = function
1672+ | [] ->
1673+ (* split is only called when [arity >= 1] *)
1674+ assert false
1675+ | first :: rest ->
1676+ first, rest
1677+ in
1678+ let prim =
1679+ match op with
1680+ | Load -> Patomic_load {immediate_or_pointer = Pointer }
1681+ | Set -> Patomic_set {immediate_or_pointer = Pointer }
1682+ | Compare_exchange -> Patomic_compare_exchange {immediate_or_pointer= Pointer }
1683+ | Exchange -> Patomic_exchange {immediate_or_pointer= Pointer }
1684+ | Cas -> Patomic_compare_set {immediate_or_pointer= Pointer }
1685+ | Faa -> Patomic_fetch_add
1686+ | Add -> Patomic_add
1687+ | Sub -> Patomic_sub
1688+ | Lor -> Patomic_lor
1689+ | Lxor -> Patomic_lxor
1690+ | Land -> Patomic_land
1691+ in
1692+ match kind with
1693+ | Ref ->
1694+ (* the primitive application
1695+ [Lprim(%atomic_exchange, [ref; v])]
1696+ becomes
1697+ [Lprim(caml_atomic_exchange_field, [ref; 0; v])]
1698+ *)
1699+ let ref_arg, rest = split args in
1700+ let args = ref_arg :: Lconst (Lambda. const_int 0 ) :: rest in
1701+ Lprim (prim, args, loc)
1702+ | Field ->
1703+ (* the primitive application
1704+ [Lprim(%atomic_exchange_field, [ptr; ofs; v])]
1705+ becomes
1706+ [Lprim(caml_atomic_exchange_field, [ptr; ofs; v])] *)
1707+ Lprim (prim, args, loc)
1708+ | Loc ->
1709+ (* CR melse: unboxed tuple? *)
1710+ (* the primitive application
1711+ [Lprim(%atomic_exchange_loc, [(ptr, ofs); v])]
1712+ becomes
1713+ [Lprim(caml_atomic_exchange_field, [ptr; ofs; v])]
1714+ and in the general case of a non-tuple expression <loc>
1715+ [Lprim(%atomic_exchange_loc, [loc; v])]
1716+ becomes
1717+ [Llet(p, loc,
1718+ Lprim(caml_atomic_exchange_field, [Field(p, 0); Field(p, 1); v]))]
1719+ *)
1720+ let loc_arg, rest = split args in
1721+ match loc_arg with
1722+ | Lprim (Pmakeblock _ , [ptr ; ofs ], _argloc ) ->
1723+ let args = ptr :: ofs :: rest in
1724+ Lprim (prim, args, loc)
1725+ | _ ->
1726+ let varg = Ident. create_local " atomic_arg" in
1727+ let ptr = Lprim (Pfield (0 , Pointer , Reads_agree ), [Lvar varg], loc) in
1728+ let ofs =
1729+ Lprim (Pfield (1 , Immediate , Reads_agree ), [Lvar varg], loc)
1730+ in
1731+ let args = ptr :: ofs :: rest in
1732+ Llet (Strict , Pvalue { raw_kind = Pgenval ; nullable = Non_nullable }, varg, loc_arg, Lprim (prim, args, loc))
1733+
16271734let caml_restore_raw_backtrace =
16281735 Lambda. simple_prim_on_values ~name: " caml_restore_raw_backtrace" ~arity: 2
16291736 ~alloc: false
@@ -1721,6 +1828,8 @@ let lambda_of_prim prim_name prim loc args arg_exps =
17211828 Lprim (Ppeek layout, [ptr], loc)
17221829 | Poke (Some layout ), [ptr; new_value] ->
17231830 Lprim (Ppoke layout, [ptr; new_value], loc)
1831+ | Atomic (op , kind ), args ->
1832+ lambda_of_atomic prim_name loc op kind args
17241833 | Unsupported prim , _ ->
17251834 let exn =
17261835 transl_extension_path loc (Lazy. force Env. initial)
@@ -1773,6 +1882,7 @@ let check_primitive_arity loc p =
17731882 | Frame_pointers -> p.prim_arity = 0
17741883 | Identity | Peek _ -> p.prim_arity = 1
17751884 | Apply _ | Revapply _ | Poke _ -> p.prim_arity = 2
1885+ | Atomic (op , kind ) -> p.prim_arity = atomic_arity op kind
17761886 | Unsupported _ -> true
17771887 in
17781888 if not ok then raise(Error (loc, Wrong_arity_builtin_primitive p.prim_name))
@@ -1972,7 +2082,7 @@ let primitive_needs_event_after = function
19722082 | Lazy_force _ | Send _ | Send_self _ | Send_cache _
19732083 | Apply _ | Revapply _ -> true
19742084 | Raise _ | Raise_with_backtrace | Loc _ | Frame_pointers | Identity
1975- | Peek _ | Poke _ | Unsupported _ -> false
2085+ | Peek _ | Poke _ | Atomic _ | Unsupported _ -> false
19762086
19772087let transl_primitive_application loc p env ty ~poly_mode ~stack ~poly_sort
19782088 path exp args arg_exps pos =
0 commit comments