Skip to content

Commit 6dfcba6

Browse files
Merge pull request #1744 from HadrienRenaud/fix-ambiguous-po-regs
[herd,asl] Fix ambiguous PC writes This PR cherry picks a commit from #1735 that introduces some checks on the coherence of writes, and fixes the problems highlighted from those checks. ## PC handling in ASL+herd The aarch64 handwritten semantics in herd handle the program counter differently from the ASL code: the ASL code has an explicit PC register, whereas the handwritten semantics rely on po and BCC branching events. We had introduced in #711 an AArch64 PC register in ASL to support the ASL code that uses it. This implementation wrote 2 times to the PC: 1. First at the beginning of the instruction to correctly initialize the PC value 2. Secondly when the branching is committed and we actually increments the PC This poses a few problems, mainly because the current herd algorithm does not handle multiple writes at the same register in a single instruction. We thus remove the translation of the PC accesses, replaced here by a BCC commit event in case of a write. This leaves implicit the PC reads. ## Intra-Instruction Dependencies starting from a register write The PC handling described above had a strange graph, where a `iico_data` was starting at a register write. This is because this register write was read-from in the same instruction. (Precisely, the first write to PC was read from to query the current PC and then increment it, resulting in a graph like [the one](https://github.com/user-attachments/files/25799596/A.pdf) shown by Luc in [a comment](#1735 (comment)) on #1704). We simply add guards on the Intra-Instruction Data dependencies to force them to start at a register read or at a memory read.
2 parents 003ec32 + e1e5b05 commit 6dfcba6

File tree

4 files changed

+92
-54
lines changed

4 files changed

+92
-54
lines changed

herd/AArch64ASLSem.ml

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,6 @@ module Make (TopConf : AArch64Sig.Config) (V : Value.AArch64ASL) :
215215
let open Asllib.AST in
216216
let with_pos desc = Asllib.ASTUtils.add_dummy_annotation ~version:V0 desc in
217217
let ( ^= ) x e = S_Decl (LDK_Let, LDI_Var x, None, Some e) |> with_pos in
218-
let ( ^^= ) x e =
219-
let le_x = LE_Var x |> with_pos in
220-
S_Assign (le_x, e) |> with_pos in
221218
let lit v = E_Literal v |> with_pos in
222219
let liti i = lit (L_Int (Z.of_int i)) in
223220
let litb b = lit (L_Bool b) in
@@ -249,7 +246,7 @@ module Make (TopConf : AArch64Sig.Config) (V : Value.AArch64ASL) :
249246
stmt
250247
[
251248
"offset" ^= litbv 64 off;
252-
"_PC" ^^= litbv 64 ii.A.addr; ])
249+
])
253250
| I_CBZ (v,rt,lab)
254251
| I_CBNZ (v,rt,lab) as i
255252
->
@@ -266,7 +263,6 @@ module Make (TopConf : AArch64Sig.Config) (V : Value.AArch64ASL) :
266263
"t" ^= reg rt;
267264
"datasize" ^= variant v;
268265
"offset" ^= litbv 64 off;
269-
"_PC" ^^= litbv 64 ii.A.addr;
270266
])
271267
| I_BC (c,lab)
272268
->
@@ -277,7 +273,6 @@ module Make (TopConf : AArch64Sig.Config) (V : Value.AArch64ASL) :
277273
[
278274
"offset" ^= litbv 64 off;
279275
"condition" ^= cond c;
280-
"_PC" ^^= litbv 64 ii.A.addr;
281276
])
282277
| I_TBZ (v, rt, k, lab)
283278
| I_TBNZ (v, rt, k, lab) ->
@@ -296,7 +291,6 @@ module Make (TopConf : AArch64Sig.Config) (V : Value.AArch64ASL) :
296291
"offset" ^= litbv 64 offset;
297292
"bit_pos" ^= liti k;
298293
"datasize" ^= variant v;
299-
"_PC" ^^= litbv 64 ii.A.addr;
300294
])
301295

302296
(* Atomic instructions *)
@@ -1126,9 +1120,13 @@ module Make (TopConf : AArch64Sig.Config) (V : Value.AArch64ASL) :
11261120
not is_vmsa ||
11271121
List.exists (Proc.equal ii.A.proc) TopConf.procs_user in
11281122
let pstate_val, eqs = build_pstate_val is_el0 ii in
1123+
let pc_val =
1124+
ASLS.A.V.scalarToV (ASLScalar.bv_of_int_sized 64 ii.A.addr)
1125+
in
11291126
let st =
11301127
ASLS.A.state_empty
11311128
|> state_add (global_loc "PSTATE") pstate_val
1129+
|> state_add (global_loc "_PC") pc_val
11321130
|> List.fold_right add_arch_reg_if_present ASLBase.gregs
11331131
|> add_reg_if_present AArch64Base.ResAddr (global_loc "RESADDR")
11341132
|> add_reg_if_present AArch64Base.SP (global_loc "_SP_EL0")
@@ -1341,6 +1339,15 @@ module Make (TopConf : AArch64Sig.Config) (V : Value.AArch64ASL) :
13411339
Printf.eprintf "tr_action %s\n%!"
13421340
(ASLS.Act.pp_action act) in
13431341
match act with
1342+
| ASLS.Act.Access
1343+
( d,
1344+
ASLS.A.Location_reg (_proc, ASLBase.ArchReg AArch64Base.PC),
1345+
v,
1346+
_,
1347+
_ ) -> (
1348+
match d with
1349+
| Dir.W -> Some (Act.Commit (Act.Bcc, Some (V.pp true (tr_v v))))
1350+
| Dir.R -> None)
13441351
| ASLS.Act.Access (dir, loc, v, sz, (a, exp, acc)) -> (
13451352
match tr_loc ii loc with
13461353
| None -> None
@@ -1542,35 +1549,22 @@ module Make (TopConf : AArch64Sig.Config) (V : Value.AArch64ASL) :
15421549
let bds = List.fold_left one_event [] event_list in
15431550
let finals = get_cat_show Misc.identity "AArch64_Finals" in
15441551
let pc =
1545-
let n_pc = (* Count writes to PC *)
1546-
List.fold_left
1547-
(fun c (r,_) ->
1548-
match r with
1549-
| AArch64Base.PC -> c+1
1550-
| _ -> c)
1551-
0 bds in
1552-
(* Branching instructions all generate one, initial,
1553-
* PC assignement and a second PC assignement
1554-
* that gives the branch target. This applies even
1555-
* for non-taken conditional branches where
1556-
* the second assignment is to the next instruction.
1557-
* This second write event is the final write to PC.
1558-
* Non-branching instructions neither read nor
1559-
* write the PC, cf. case [None] below.
1560-
*)
1561-
if n_pc <= 1 then None
1562-
else
1563-
ESet.fold
1564-
(fun e r ->
1565-
match e.ASLE.action with
1566-
| ASLS.Act.Access
1567-
(Dir.W,
1568-
ASLS.A.Location_reg
1569-
(_,
1570-
ASLBase.ArchReg AArch64Base.PC), v, _, _) ->
1571-
Some (tr_v v)
1572-
| _ -> r)
1573-
finals None in
1552+
ESet.fold
1553+
(fun e r ->
1554+
match e.ASLE.action with
1555+
| ASLS.Act.Access
1556+
( Dir.W,
1557+
ASLS.A.Location_reg (_, ASLBase.ArchReg AArch64Base.PC),
1558+
v,
1559+
_,
1560+
_ ) ->
1561+
if Option.is_some r then
1562+
Warn.fatal
1563+
"There are 2 direct writes to PC in this instruction.";
1564+
Some (tr_v v)
1565+
| _ -> r)
1566+
finals None
1567+
in
15741568
match Misc.seq_opt A.V.as_int pc with
15751569
| Some v -> B.Jump (B.Addr v,bds)
15761570
| None ->

herd/libdir/asl.cat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ let asl_ctrl_deps = [B]; (asl_data | asl_iico_ctrl)+; [AArch64]
5050
(**********************************)
5151

5252
(* Intra-instruction Data dependencies *)
53-
let aarch64_iico_data = [AArch64 \ B]; asl_deps; [AArch64]
53+
let aarch64_iico_data = [AArch64 & (R | Rreg)]; asl_deps; [AArch64]
5454

5555
(* Intra-instruction Control dependencies *)
5656
let aarch64_iico_ctrl = [B]; asl_ctrl_deps; [AArch64]

herd/mem.ml

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -864,27 +864,71 @@ and get_written e = match E.written_of e with
864864
(* Compute rfmap for registers *)
865865
(*******************************)
866866

867+
module EvtSetByPo (I : sig
868+
val es : S.event_structure
869+
end) =
870+
struct
871+
let is_before_strict = U.is_before_strict I.es
872+
873+
let ambiguous_po e1 e2 =
874+
Warn.fatal "Ambiguous po for register %s: %s and %s are not ordered.\n%!"
875+
(A.pp_location (get_loc e1))
876+
(E.debug_event_str e1) (E.debug_event_str e2)
877+
878+
include Set.Make (struct
879+
type t = E.event
880+
881+
let compare e1 e2 =
882+
if is_before_strict e1 e2 then -1
883+
else if is_before_strict e2 e1 then 1
884+
else ambiguous_po e1 e2
885+
end)
886+
887+
let find_last_before e set =
888+
find_last_opt (fun e' -> is_before_strict e' e) set
889+
890+
let find_first_after e set =
891+
find_first_opt (fun e' -> is_before_strict e e') set
892+
[@@warning "-32"]
893+
894+
(* We have to check that the order is total because none of the set
895+
construction methods perform enough comparison to ensure that all
896+
consecutive elements will be compared.
897+
898+
Checking that all consecutive elements are comparable is enough to prove
899+
totality if the relation is transitive. Here, we believe that
900+
[is_before_strict] is transitive by construction.
901+
902+
See this gist:
903+
https://gist.github.com/HadrienRenaud/245295e0950fb3b58c23e43937248c9c
904+
*)
905+
906+
let check_total set =
907+
if not (is_empty set) then
908+
fold
909+
(fun e pred_opt ->
910+
match pred_opt with
911+
| Some pred ->
912+
if not (is_before_strict pred e) then ambiguous_po e pred;
913+
Some e
914+
| None -> Some e)
915+
set None
916+
|> ignore
917+
918+
let of_list li =
919+
let set = of_list li in
920+
let () = check_total set in
921+
set
922+
end
923+
867924
let map_loc_find loc m =
868925
try U.LocEnv.find loc m
869926
with Not_found -> []
870927

871928
let match_reg_events add_eq es csn =
872929
let loc_loads_stores = U.collect_reg_loads_stores es in
873-
let is_before_strict = U.is_before_strict es in
874-
let compare e1 e2 =
875-
if is_before_strict e1 e2 then -1
876-
else if is_before_strict e2 e1 then 1
877-
else
878-
let () =
879-
Printf.eprintf "Not ordered stores %a and %a\n" E.debug_event e1
880-
E.debug_event e2
881-
in
882-
assert false
883-
in
884-
let module StoreSet = Set.Make (struct
885-
type t = E.event
886-
887-
let compare = compare
930+
let module StoreSet = EvtSetByPo (struct
931+
let es = es
888932
end) in
889933
let add wt rf (rfm, csn) = (S.RFMap.add wt rf rfm, add_eq rfm wt rf csn) in
890934
(* For all loads find the right store, the one "just before" the load *)
@@ -901,9 +945,8 @@ let match_reg_events add_eq es csn =
901945
(* Add the corresponding store for each load *)
902946
List.fold_left
903947
(fun k load ->
904-
let f e = is_before_strict e load in
905948
let rf =
906-
match StoreSet.find_last_opt f stores with
949+
match StoreSet.find_last_before load stores with
907950
| Some store -> S.Store store
908951
| None -> S.Init
909952
in

lib/ASLScalar.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ let zeros_size_one = S_BitVector (BV.zeros 1)
393393
let bv_of_bool b = S_BitVector (if b then BV.one else BV.zero)
394394

395395
let bv_of_int x = S_BitVector (BV.of_int x)
396+
let bv_of_int_sized n x = S_BitVector (BV.of_int_sized n x)
396397

397398
let do_bv_of_bit = function
398399
| 0 -> BV.zero

0 commit comments

Comments
 (0)