@@ -77,6 +77,20 @@ type loc_kind =
7777 | Loc_POS
7878 | Loc_FUNCTION
7979
80+ type atomic_kind =
81+ | Ref (* operation on an atomic reference
82+ (takes only a pointer) *)
83+ | Record (* operation on an atomic record
84+ (takes a pointer and an offset) *)
85+ | Loc (* operation on a first-class field
86+ (takes a (pointer, offset) pair *)
87+
88+ type atomic_op =
89+ | Load
90+ | Exchange
91+ | Cas
92+ | Fetch_add
93+
8094type prim =
8195 | Primitive of Lambda .primitive * int
8296 | External of Primitive .description
@@ -92,6 +106,7 @@ type prim =
92106 | Identity
93107 | Apply
94108 | Revapply
109+ | Atomic of atomic_op * atomic_kind
95110
96111let used_primitives = Hashtbl. create 7
97112let add_used_primitive loc env path =
@@ -114,12 +129,11 @@ let prim_sys_argv =
114129 Primitive. simple ~name: " caml_sys_argv" ~arity: 1 ~alloc: true
115130
116131let prim_atomic_exchange =
117- Primitive. simple ~name: " caml_atomic_exchange " ~arity: 2 ~alloc: false
132+ Primitive. simple ~name: " caml_atomic_exchange_field " ~arity: 3 ~alloc: false
118133let prim_atomic_cas =
119- Primitive. simple ~name: " caml_atomic_cas " ~arity: 3 ~alloc: false
134+ Primitive. simple ~name: " caml_atomic_cas_field " ~arity: 4 ~alloc: false
120135let prim_atomic_fetch_add =
121- Primitive. simple ~name: " caml_atomic_fetch_add" ~arity: 2 ~alloc: false
122-
136+ Primitive. simple ~name: " caml_atomic_fetch_add_field" ~arity: 3 ~alloc: false
123137
124138let primitives_table =
125139 create_hashtable 57 [
@@ -372,10 +386,18 @@ let primitives_table =
372386 " %greaterequal" , Comparison (Greater_equal , Compare_generic );
373387 " %greaterthan" , Comparison (Greater_than , Compare_generic );
374388 " %compare" , Comparison (Compare , Compare_generic );
375- " %atomic_load" , Primitive (Patomic_load , 1 );
376- " %atomic_exchange" , External prim_atomic_exchange;
377- " %atomic_cas" , External prim_atomic_cas;
378- " %atomic_fetch_add" , External prim_atomic_fetch_add;
389+ " %atomic_load" , Atomic (Load , Ref );
390+ " %atomic_exchange" , Atomic (Exchange , Ref );
391+ " %atomic_cas" , Atomic (Cas , Ref );
392+ " %atomic_fetch_add" , Atomic (Fetch_add , Ref );
393+ " %atomic_load_field" , Atomic (Load , Record );
394+ " %atomic_exchange_field" , Atomic (Exchange , Record );
395+ " %atomic_cas_field" , Atomic (Cas , Record );
396+ " %atomic_fetch_add_field" , Atomic (Fetch_add , Record );
397+ " %atomic_load_loc" , Atomic (Load , Loc );
398+ " %atomic_exchange_loc" , Atomic (Exchange , Loc );
399+ " %atomic_cas_loc" , Atomic (Cas , Loc );
400+ " %atomic_fetch_add_loc" , Atomic (Fetch_add , Loc );
379401 " %runstack" , Primitive (Prunstack , 3 );
380402 " %reperform" , Primitive (Preperform , 3 );
381403 " %perform" , Primitive (Pperform , 1 );
@@ -658,6 +680,75 @@ let lambda_of_loc kind sloc =
658680 let scope_name = Debuginfo.Scoped_location. string_of_scoped_location sloc in
659681 Lconst (Const_immstring scope_name)
660682
683+ let atomic_arity (op : atomic_op ) (kind : atomic_kind ) =
684+ let arity_of_op = match op with
685+ | Load -> 1
686+ | Exchange -> 2
687+ | Cas -> 3
688+ | Fetch_add -> 2
689+ in
690+ let extra_kind_arity = match kind with
691+ | Ref | Loc -> 0
692+ | Record -> 1
693+ in
694+ arity_of_op + extra_kind_arity
695+
696+ let lambda_of_atomic prim_name loc op kind args =
697+ if List. length args <> atomic_arity op kind then
698+ raise(Error (to_location loc,
699+ Wrong_arity_builtin_primitive prim_name));
700+ let split = function
701+ | [] ->
702+ (* split is only called when [arity >= 1] *)
703+ assert false
704+ | first :: rest -> first, rest
705+ in
706+ let prim = match (op : atomic_op ) with
707+ | Load -> Patomic_load
708+ | Exchange -> Pccall prim_atomic_exchange
709+ | Cas -> Pccall prim_atomic_cas
710+ | Fetch_add -> Pccall prim_atomic_fetch_add
711+ in
712+ match (kind : atomic_kind ) with
713+ | Record ->
714+ (* the primitive application
715+ [%atomic_exchange_field ptr ofs v]
716+ becomes (in pseudo-code mixing C calls and OCaml expressions)
717+ [caml_atomic_exchange_field(ptr, ofs, v)] *)
718+ Lprim (prim, args, loc)
719+ | Ref ->
720+ (* the primitive application
721+ [%atomic_exchange ref v]
722+ becomes
723+ [caml_atomic_exchange_field(ref, Val_long(0), v)] *)
724+ let ref_arg, rest = split args in
725+ let args = ref_arg :: Lconst (Lambda. const_int 0 ) :: rest in
726+ Lprim (prim, args, loc)
727+ | Loc ->
728+ (* the primitive application
729+ [%atomic_exchange_loc (ptr, ofs) v]
730+ becomes
731+ [caml_atomic_exchange_field(ptr, ofs, v)]
732+ and in the general case of a non-tuple expression <loc>
733+ [%atomic_exchange_loc <loc> v]
734+ becomes
735+ [let p = <loc> in
736+ caml_atomic_exchange_field(Field(p, 0), Field(p, 1), v)] *)
737+ let loc_arg, rest = split args in
738+ match loc_arg with
739+ | Lprim (Pmakeblock _ , [ptr ; ofs ], _argloc ) ->
740+ let args = ptr :: ofs :: rest in
741+ Lprim (prim, args, loc)
742+ | _ ->
743+ let varg = Ident. create_local " atomic_arg" in
744+ let ptr = Lprim (Pfield (0 , Pointer , Immutable ),
745+ [Lvar varg], loc) in
746+ let ofs = Lprim (Pfield (1 , Immediate , Immutable ),
747+ [Lvar varg], loc) in
748+ let args = ptr :: ofs :: rest in
749+ Llet (Strict , Pgenval , varg, loc_arg,
750+ Lprim (prim, args, loc))
751+
661752let caml_restore_raw_backtrace =
662753 Primitive. simple ~name: " caml_restore_raw_backtrace" ~arity: 2 ~alloc: false
663754
@@ -744,10 +835,13 @@ let lambda_of_prim prim_name prim loc args arg_exps =
744835 ap_inlined = Default_inline ;
745836 ap_specialised = Default_specialise ;
746837 }
838+ | Atomic (op , kind ), args ->
839+ lambda_of_atomic prim_name loc op kind args
747840 | (Raise _ | Raise_with_backtrace
748841 | Lazy_force | Loc _ | Primitive _ | Comparison _
749842 | Send | Send_self | Send_cache | Frame_pointers | Identity
750- | Apply | Revapply ), _ ->
843+ | Apply | Revapply
844+ ), _ ->
751845 raise(Error (to_location loc, Wrong_arity_builtin_primitive prim_name))
752846
753847let check_primitive_arity loc p =
@@ -766,6 +860,7 @@ let check_primitive_arity loc p =
766860 | Frame_pointers -> p.prim_arity = 0
767861 | Identity -> p.prim_arity = 1
768862 | Apply | Revapply -> p.prim_arity = 2
863+ | Atomic (op , kind ) -> p.prim_arity = atomic_arity op kind
769864 in
770865 if not ok then raise(Error (loc, Wrong_arity_builtin_primitive p.prim_name))
771866
@@ -838,7 +933,11 @@ let primitive_needs_event_after = function
838933 lambda_primitive_needs_event_after (comparison_primitive comp knd)
839934 | Lazy_force | Send | Send_self | Send_cache
840935 | Apply | Revapply -> true
841- | Raise _ | Raise_with_backtrace | Loc _ | Frame_pointers | Identity -> false
936+ | Raise _ | Raise_with_backtrace
937+ | Loc _
938+ | Frame_pointers | Identity
939+ | Atomic (_, _)
940+ -> false
842941
843942let transl_primitive_application loc p env ty path exp args arg_exps =
844943 let prim =
0 commit comments