@@ -267,6 +267,8 @@ and module RMW = A.RMW = struct
267267
268268 type edge = { edge : tedge ; a1 :atom option ; a2 : atom option ; }
269269
270+ let can_merge e = not @@ is_insert_store e.edge
271+
270272 open Printf
271273
272274 let plain_edge e = { a1= None ; a2= None ; edge= e; }
@@ -367,16 +369,12 @@ let pp_dp_default tag sd e = sprintf "%s%s%s" tag (pp_sd sd) (pp_extr e)
367369 | CRf |CWs -> Dir W
368370 | CFr -> Dir R
369371
370- exception NotThat of string
371-
372- let not_that e msg = raise (NotThat (sprintf " %s: %s" msg (pp_tedge e)))
373-
374372 let do_dir_tgt e = match e with
375373 | Po (_ ,_ ,e )| Fenced (_ ,_ ,_ ,e )|Dp (_ ,_ ,e ) -> e
376374 | Rf _ | Hat -> Dir R
377375 | Ws _ |Fr _ |Rmw _ -> Dir W
378376 | Leave c |Back c -> do_dir_tgt_com c
379- | Id -> not_that e " do_dir_tgt "
377+ | Id -> NoDir
380378 | Insert _ -> NoDir
381379 | Store -> Dir W
382380 | Node d -> Dir d
@@ -387,7 +385,7 @@ let pp_dp_default tag sd e = sprintf "%s%s%s" tag (pp_sd sd) (pp_extr e)
387385 | Dp _ |Fr _ |Hat |Rmw _ -> Dir R
388386 | Ws _ |Rf _ -> Dir W
389387 | Leave c |Back c -> do_dir_src_com c
390- | Id -> not_that e " do_dir_src "
388+ | Id -> NoDir
391389 | Insert _ -> NoDir
392390 | Store -> Dir W
393391 | Node d -> Dir d
@@ -530,12 +528,9 @@ let fold_tedges f r =
530528 let dir_tgt e = do_dir_tgt e.edge
531529 and dir_src e = do_dir_src e.edge
532530 and safe_dir e =
533- try
534- begin match do_dir_src e.edge with
535- | Dir d -> Some d
536- | NoDir |Irr -> None
537- end
538- with NotThat _ -> None
531+ match do_dir_src e.edge with
532+ | Dir d -> Some d
533+ | NoDir |Irr -> None
539534
540535(* **************)
541536(* Atom lexing *)
@@ -803,15 +798,13 @@ let fold_tedges f r =
803798 let expand_edges es f = do_expand_edges (List. rev es) f []
804799
805800(* resolve *)
806- let rec find_non_insert_store = function
801+ let rec find_next_merge = function
807802 | [] -> raise Not_found
808- | e ::es -> begin match e.edge with
809- | Insert _ |Store ->
810- let bef,ni,aft = find_non_insert_store es in
811- e::bef,ni,aft
812- | _ ->
813- [] ,e,es
814- end
803+ | e ::es -> (* `Node` or Non-pseudo can be merged *)
804+ if can_merge e then [] ,e,es
805+ else
806+ let bef,ni,aft = find_next_merge es in
807+ e::bef,ni,aft
815808
816809 let set_a1 e a = match e.edge with
817810 | Node _ |Id -> { e with a1= a; a2= a;}
@@ -821,120 +814,65 @@ let fold_tedges f r =
821814 | Node _ |Id -> { e with a1= a; a2= a;}
822815 | _ -> { e with a2= a;}
823816
824- let merge_id e1 e2 = match e1.edge,e2.edge with
825- | Id ,Id ->
826- begin
827- let a1 = e1.a2 and a2 = e2.a1 in
828- match a1,a2 with
829- | None ,None -> Some e1
830- | (None ,(Some _ as a ))|((Some _ as a ),None) ->
831- Some { e1 with a1= a; a2= a; }
832- | Some a1 ,Some a2 ->
833- begin
834- match merge_atoms a1 a2 with
835- | None -> None (* Merge impossible, will fail later *)
836- | Some _ as a ->
837- Some { e1 with a1= a; a2= a; }
838- end
839- end
840- | _ -> None
841-
842- let merge_ids =
843- let rec do_rec fst = function
844- | [] -> fst,[]
845- | [lst] ->
846- begin
847- match merge_id lst fst with
848- | None -> fst,[lst]
849- | Some e -> e,[]
850- end
851- | e1 ::(e2 ::es as k ) ->
852- begin
853- match merge_id e1 e2 with
854- | None ->
855- let fst,k = do_rec fst k in
856- fst,e1::k
857- | Some e -> do_rec fst (e::es)
858- end in
859- let rec do_fst = function
860- | [] |[_] as es -> es
861- | e1 ::(e2 ::es as k ) ->
862- begin
863- match merge_id e1 e2 with
864- | None ->
865- let fst,k = do_rec e1 k in
866- fst::k
867- | Some e -> do_fst (e::es)
868- end in
869- do_fst
870-
871- (*
872- resolve_pair e1 e2, merges the end annotation of e1 with
873- the start annotation of e2.
874- Warning: resolve_pair cannot fail, instead it must leave
875- e1 and e2 as they are...
876- *)
877- let resolve_pair e1 e2 =
878- if dbg > 0 then
879- eprintf
880- " Resolve pair <%s,%s> -> " (debug_edge e1) (debug_edge e2) ;
881- let e1,e2 =
882- try
883- let d1 = dir_tgt e1 and d2 = dir_src e2 in
884- match d1,d2 with
885- | Irr ,Dir d -> set_tgt d e1,e2
886- | Dir d ,Irr -> e1,set_src d e2
887- | _ ,_ -> e1,e2
888- with NotThat _ -> e1,e2 in
889- let a1 = e1.a2 and a2 = e2.a1 in
890- let r =
817+ (* Merges the end annotation and direction of `e1`
818+ with the start of `e2`. *)
819+ let merge_pair e1 e2 =
820+ let update_dir (e1 ,e2 ) =
821+ let d1 = dir_tgt e1 and d2 = dir_src e2 in
822+ match d1,d2 with
823+ | Irr ,Dir d -> Some (set_tgt d e1,e2)
824+ | Dir d ,Irr -> Some (e1,set_src d e2)
825+ | _ ,_ -> None in
826+ let update_annotation (e1 ,e2 ) =
827+ let a1 = e1.a2 and a2 = e2.a1 in
891828 match a1,a2 with
892- | None ,None -> e1,e2
829+ | None ,None -> None
893830 | None ,Some a
894- | Some a ,None when is_ifetch (Some a)-> e1, e2
895- | None ,Some _ -> set_a2 e1 a2,e2
896- | Some _ ,None -> e1, set_a1 e2 a1
831+ | Some a ,None when is_ifetch (Some a)-> None
832+ | None ,Some _ -> Some ( set_a2 e1 a2,e2)
833+ | Some _ ,None -> Some ( e1, set_a1 e2 a1)
897834 | Some a1 ,Some a2 ->
898- begin match merge_atoms a1 a2 with
899- | None -> e1,e2
900- | Some _ as a ->
901- set_a2 e1 a,set_a1 e2 a
902- end in
835+ match merge_atoms a1 a2 with
836+ | None -> None
837+ | Some _ as a ->
838+ Some (set_a2 e1 a,set_a1 e2 a) in
839+ let input = (e1,e2) in
840+ let r = update_dir input
841+ |> Option. fold ~none: (update_annotation input)
842+ (* Propagate result `f e` if changed *)
843+ ~some: (fun e ->
844+ Some (Option. value (update_annotation e) ~default: e)) in
903845 if dbg > 0 then begin
904- let e1,e2 = r in
905- eprintf " <%s,%s>\n " (debug_edge e1) (debug_edge e2)
846+ let i1,i2 = input in
847+ let r1,r2 = Option. value ~default: input r in
848+ eprintf " Merge pair <%s,%s> -> <%s,%s>\n "
849+ (debug_edge i1) (debug_edge i2) (debug_edge r1) (debug_edge r2)
906850 end ;
907851 r
908852
909- (* Function merge_pair merges two versions of the same edge with
910- different annotations and direction resolution.
911- It cannot fail *)
912- let merge_dir d1 d2 = match d1,d2 with
913- | (Irr ,Dir d )|(Dir d ,Irr) -> d
914- | Dir d1 ,Dir d2 -> assert (d1= d2) ; d1
915- | (Irr ,Irr )|(NoDir ,_ )|(_ ,NoDir) -> assert false
916-
917- let merge_atomo a1 a2 = match a1,a2 with
918- | None ,Some _ -> a2
919- | Some _ ,None -> a1
920- | None ,None -> None
921- | Some a1 ,Some a2 ->
922- begin match merge_atoms a1 a2 with
923- | None ->
924- Warn. fatal
925- " Atoms %s and %s *must* be mergeable"
926- (pp_atom a1) (pp_atom a2)
927- | Some _ as a -> a
928- end
929-
930- let merge_pair e1 e2 = match e1.edge,e2.edge with
931- | (Id,Id) -> e1
932- | (Insert _ ,_ )|(_ ,Insert _ ) -> assert false
933- | _ ,_ ->
934- let tgt = merge_dir (dir_tgt e1) (dir_tgt e2)
935- and src = merge_dir (dir_src e1) (dir_src e2) in
936- let e = set_tgt tgt (set_src src e1) in
937- { e with a1 = merge_atomo e1.a1 e2.a1; a2 = merge_atomo e1.a2 e2.a2; }
853+ (* Assume `e` is not `Store` nor `Insert`,
854+ merge annotations and direction from the head of `es`
855+ into `e` until no more possibility. *)
856+ let rec merge_left e es =
857+ let is_default e = e = { edge= Id ; a1= None ; a2= None ; } in
858+ try
859+ let store_insert,next,rest = find_next_merge es in
860+ (* throw away a default annotation *)
861+ if is_default e then true , None , store_insert @ next :: rest
862+ else if is_default next then merge_left e (store_insert @ rest)
863+ (* Merge `e` and `next` *)
864+ else match merge_pair e next with
865+ | None -> true , Some e, (store_insert @ next :: rest)
866+ | Some (e , next ) ->
867+ match is_id e.edge, is_id next.edge with
868+ (* Erase `next` and continue merging *)
869+ | _ ,true -> merge_left e (store_insert @ rest)
870+ (* Indicate erasing `e` *)
871+ | true ,false -> true , None , (store_insert @ next :: rest)
872+ (* Two non-`Id` *)
873+ | false ,false -> true , Some (e), (store_insert @ next :: rest)
874+ (* find_next_merge fails, no more node to process *)
875+ with Not_found -> false , Some e, es
938876
939877 let default_access = Cfg. naturalsize,0
940878
@@ -947,69 +885,78 @@ let fold_tedges f r =
947885 and a2 = replace_plain_atom e.a2 in
948886 { e with a1; a2; }
949887
950- let remove_id = List. filter (fun e -> not (is_id e.edge))
951-
952- let check_mixed =
953- if not do_mixed || do_disjoint then fun _ -> ()
954- else
955- List. iter
956- (fun e ->
957- if not (ok_mixed e.edge e.a1 e.a2) then begin
958- match e.edge with
959- | Rmw _ ->
960- Warn. fatal
961- " Illegal mixed-size Rmw edge: %s"
962- (pp_edge e)
963- | _ ->
964- if same_access_atoms e.a1 e.a2 then
965- Warn. fatal
966- " Identical mixed access in %s and `-variant MixedStrictOverlap` mode"
967- (pp_edge e)
968- else
969- Warn. fatal
970- " Non overlapping accesses in %s, allow with `-variant MixedDisjoint`"
971- (pp_edge e)
972- end )
888+ let validity_edges es =
889+ (* Check mixed size memory access annotation *)
890+ let check_mixed e =
891+ if not (not do_mixed || do_disjoint || (ok_mixed e.edge e.a1 e.a2)) then
892+ Warn. fatal
893+ ( match e.edge,(same_access_atoms e.a1 e.a2) with
894+ | Rmw _ ,_ -> " Illegal mixed-size Rmw edge: %s"
895+ | _ ,true ->
896+ " Identical mixed access in %s and `-variant MixedStrictOverlap` mode"
897+ | _ ,false ->
898+ " Non overlapping accesses in %s, allow with `-variant MixedDisjoint`" )
899+ (pp_edge e) in
900+ (* Check `Id` edge are all pseudo annotation *)
901+ let check_pseudo_id e =
902+ if is_id e.edge then
903+ Warn. fatal " Invalid extra annotation %s" (pp_edge e) in
904+ List. iter (fun e -> check_mixed e; check_pseudo_id e) es;
905+ (* Match annotations between non-insert edges *)
906+ let last_non_insert_edge =
907+ List. rev es
908+ |> List. find ( fun e -> not @@ is_insert_store e.edge ) in
909+ List. fold_left (fun prev_annotation e ->
910+ match is_insert_store e.edge, prev_annotation = e.a1 with
911+ (* carry over the previous result if insert edges *)
912+ | true ,_ -> prev_annotation
913+ | false ,false -> Warn. fatal " Annotations mismatch"
914+ | false ,true -> e.a2
915+ ) last_non_insert_edge.a2 es
916+ |> ignore
917+
973918
974919 let resolve_edges es0 =
975- let es0 = merge_ids es0 in
976- match es0 with
977- | [] |[_] -> es0
978- | e ::es ->
979- let rec do_rec e es = match e.edge with
980- | Insert _ |Store ->
981- let fst,nxt,es = do_recs es in
982- fst,e,nxt::es
983- | _ ->
984- begin try
985- let es0,e1,es1 = find_non_insert_store es in
986- let e,e1 = resolve_pair e e1 in
987- let fst,f,es = do_recs (es0@ (e1::es1)) in
988- fst,e,f::es
989- with Not_found -> try
990- let _,e1,_ = find_non_insert_store es0 in
991- let e,e1 = resolve_pair e e1 in
992- e1,e,es
993- with Not_found -> Warn. user_error " No non-insert-store node in cycle"
994- end
995- and do_recs = function
996- (* This case is handled by Not_found handler above *)
997- | [] -> assert false
998- | e ::es -> do_rec e es in
999- let fst,e,es = do_rec e es in
1000- let e =
1001- match e.edge with
1002- | Insert _ -> e
1003- | _ ->
1004- try merge_pair fst e
1005- with exn ->
1006- eprintf " Failure <%s,%s>\n " (debug_edge fst) (debug_edge e) ;
1007- raise exn in
1008- let es = remove_id (e::es) in
1009- let es = if do_mixed then List. map replace_plain es else es in
1010- if dbg > 0 then eprintf " Check Mixed: %s\n " (pp_edges es) ;
1011- check_mixed es ;
1012- es
920+ (* Merge annotations until find a first node
921+ that is not `Id`, `Store` nor `Insert`. *)
922+ let rec find_first es =
923+ let before,fst,after =
924+ try find_next_merge es
925+ with Not_found -> Warn. user_error " No memory access node in cycle" in
926+ let continuation,fst,after = merge_left fst after in
927+ match continuation,fst with
928+ | false , _ ->
929+ Warn. user_error " Only one relaxation that is not store nor insert."
930+ | true , None ->
931+ let before',fst,after = find_first after in
932+ before @ before',fst,after
933+ | true , Some (fst ) -> before,fst,after in
934+ (* merge annotations in `es`, where `fst` is used to merge both the hand and tail of `es` *)
935+ let rec merge_es fst es = match es with
936+ | [] -> fst, []
937+ | e ::es ->
938+ if can_merge e then
939+ let continuation,e,es = merge_left e es in
940+ match continuation,e with
941+ | false , None -> assert false
942+ (* throw away `e` *)
943+ | true , None -> merge_es fst es
944+ | true , Some (e ) ->
945+ let fst,es = merge_es fst es in
946+ fst,e::es
947+ | false , Some (e ) ->
948+ (* Reach the last relax, will try to merge with `fst` *)
949+ let e,fst = merge_pair e fst |> Option. value ~default: (e,fst) in
950+ fst,e::es
951+ else
952+ let fst,es = merge_es fst es in fst,e::es in
953+ let before,fst,es = find_first es0 in
954+ let fst,es = merge_es fst es in
955+ let es = before @ fst :: es in
956+ let es = if do_mixed then List. map replace_plain es else es in
957+ if dbg > 0 then eprintf " Check Validity: %s\n " (pp_edges es) ;
958+ validity_edges es ;
959+ es
1013960
1014961(* *******************)
1015962(* Atomic variation *)
0 commit comments