@@ -77,6 +77,20 @@ type loc_kind =
77
77
| Loc_POS
78
78
| Loc_FUNCTION
79
79
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
+
80
94
type prim =
81
95
| Primitive of Lambda .primitive * int
82
96
| External of Primitive .description
@@ -92,6 +106,7 @@ type prim =
92
106
| Identity
93
107
| Apply
94
108
| Revapply
109
+ | Atomic of atomic_op * atomic_kind
95
110
96
111
let used_primitives = Hashtbl. create 7
97
112
let add_used_primitive loc env path =
@@ -114,12 +129,11 @@ let prim_sys_argv =
114
129
Primitive. simple ~name: " caml_sys_argv" ~arity: 1 ~alloc: true
115
130
116
131
let 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
118
133
let 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
120
135
let 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
123
137
124
138
let primitives_table =
125
139
create_hashtable 57 [
@@ -372,10 +386,18 @@ let primitives_table =
372
386
" %greaterequal" , Comparison (Greater_equal , Compare_generic );
373
387
" %greaterthan" , Comparison (Greater_than , Compare_generic );
374
388
" %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 );
379
401
" %runstack" , Primitive (Prunstack , 3 );
380
402
" %reperform" , Primitive (Preperform , 3 );
381
403
" %perform" , Primitive (Pperform , 1 );
@@ -658,6 +680,75 @@ let lambda_of_loc kind sloc =
658
680
let scope_name = Debuginfo.Scoped_location. string_of_scoped_location sloc in
659
681
Lconst (Const_immstring scope_name)
660
682
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
+
661
752
let caml_restore_raw_backtrace =
662
753
Primitive. simple ~name: " caml_restore_raw_backtrace" ~arity: 2 ~alloc: false
663
754
@@ -744,10 +835,13 @@ let lambda_of_prim prim_name prim loc args arg_exps =
744
835
ap_inlined = Default_inline ;
745
836
ap_specialised = Default_specialise ;
746
837
}
838
+ | Atomic (op , kind ), args ->
839
+ lambda_of_atomic prim_name loc op kind args
747
840
| (Raise _ | Raise_with_backtrace
748
841
| Lazy_force | Loc _ | Primitive _ | Comparison _
749
842
| Send | Send_self | Send_cache | Frame_pointers | Identity
750
- | Apply | Revapply ), _ ->
843
+ | Apply | Revapply
844
+ ), _ ->
751
845
raise(Error (to_location loc, Wrong_arity_builtin_primitive prim_name))
752
846
753
847
let check_primitive_arity loc p =
@@ -766,6 +860,7 @@ let check_primitive_arity loc p =
766
860
| Frame_pointers -> p.prim_arity = 0
767
861
| Identity -> p.prim_arity = 1
768
862
| Apply | Revapply -> p.prim_arity = 2
863
+ | Atomic (op , kind ) -> p.prim_arity = atomic_arity op kind
769
864
in
770
865
if not ok then raise(Error (loc, Wrong_arity_builtin_primitive p.prim_name))
771
866
@@ -838,7 +933,11 @@ let primitive_needs_event_after = function
838
933
lambda_primitive_needs_event_after (comparison_primitive comp knd)
839
934
| Lazy_force | Send | Send_self | Send_cache
840
935
| 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
842
941
843
942
let transl_primitive_application loc p env ty path exp args arg_exps =
844
943
let prim =
0 commit comments