Skip to content
Snippets Groups Projects
Commit 72f346ba authored by xleroy's avatar xleroy
Browse files

New linearization heuristic

git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@1001 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e
parent 2837d6de
No related branches found
No related tags found
No related merge requests found
...@@ -45,39 +45,79 @@ let rec pos_of_int n = ...@@ -45,39 +45,79 @@ let rec pos_of_int n =
then Coq_xO (pos_of_int (n lsr 1)) then Coq_xO (pos_of_int (n lsr 1))
else Coq_xI (pos_of_int (n lsr 1)) else Coq_xI (pos_of_int (n lsr 1))
(* Build the enumeration *)
module IntSet = Set.Make(struct type t = int let compare = compare end) module IntSet = Set.Make(struct type t = int let compare = compare end)
let enumerate_aux f reach = (* Determine join points: reachable nodes that have > 1 predecessor *)
let enum = ref [] in
let emitted = Array.make (int_of_pos f.fn_nextpc) false in let join_points f =
let rec emit_block pending pc = let reached = ref IntSet.empty in
let reached_twice = ref IntSet.empty in
let rec traverse pc =
let npc = int_of_pos pc in
if IntSet.mem npc !reached then begin
if not (IntSet.mem npc !reached_twice) then
reached_twice := IntSet.add npc !reached_twice
end else begin
reached := IntSet.add npc !reached;
List.iter traverse (LTL.successors f pc)
end
in traverse f.fn_entrypoint; !reached_twice
(* Cut into reachable basic blocks, annotated with the min value of the PC *)
let basic_blocks f joins =
let blocks = ref [] in
let visited = ref IntSet.empty in
(* start_block:
pc is the function entry point
or a join point
or the successor of a conditional test *)
let rec start_block pc =
let npc = int_of_pos pc in let npc = int_of_pos pc in
if emitted.(npc) if not (IntSet.mem npc !visited) then begin
then emit_restart pending visited := IntSet.add npc !visited;
else begin in_block [] max_int pc
enum := pc :: !enum;
emitted.(npc) <- true;
match PTree.get pc f.fn_code with
| None -> assert false
| Some i ->
match i with
| Lnop s -> emit_block pending s
| Lop (op, args, res, s) -> emit_block pending s
| Lload (chunk, addr, args, dst, s) -> emit_block pending s
| Lstore (chunk, addr, args, src, s) -> emit_block pending s
| Lcall (sig0, ros, args, res, s) -> emit_block pending s
| Ltailcall (sig0, ros, args) -> emit_restart pending
| Lcond (cond, args, ifso, ifnot) ->
emit_restart (IntSet.add (int_of_pos ifso)
(IntSet.add (int_of_pos ifnot) pending))
| Lreturn optarg -> emit_restart pending
end end
and emit_restart pending = (* in_block: add pc to block and check successors *)
if not (IntSet.is_empty pending) then begin and in_block blk minpc pc =
let npc = IntSet.max_elt pending in let npc = int_of_pos pc in
emit_block (IntSet.remove npc pending) (pos_of_int npc) let blk = pc :: blk in
end in let minpc = min npc minpc in
emit_block IntSet.empty f.fn_entrypoint; match PTree.get pc f.fn_code with
List.rev !enum | None -> assert false
| Some i ->
match i with
| Lnop s -> next_in_block blk minpc s
| Lop (op, args, res, s) -> next_in_block blk minpc s
| Lload (chunk, addr, args, dst, s) -> next_in_block blk minpc s
| Lstore (chunk, addr, args, src, s) -> next_in_block blk minpc s
| Lcall (sig0, ros, args, res, s) -> next_in_block blk minpc s
| Ltailcall (sig0, ros, args) -> end_block blk minpc
| Lcond (cond, args, ifso, ifnot) ->
end_block blk minpc; start_block ifso; start_block ifnot
| Lreturn optarg -> end_block blk minpc
(* next_in_block: check if join point and either extend block
or start block *)
and next_in_block blk minpc pc =
let npc = int_of_pos pc in
if IntSet.mem npc joins
then (end_block blk minpc; start_block pc)
else in_block blk minpc pc
(* end_block: record block that we just discovered *)
and end_block blk minpc =
blocks := (minpc, List.rev blk) :: !blocks
in
start_block f.fn_entrypoint; !blocks
(* Flatten basic blocks in decreasing order of minpc *)
let flatten_blocks blks =
let cmp_minpc (mpc1, _) (mpc2, _) =
if mpc1 = mpc2 then 0 else if mpc1 > mpc2 then -1 else 1
in
List.flatten (List.map Pervasives.snd (List.sort cmp_minpc blks))
(* Build the enumeration *)
let enumerate_aux f reach =
flatten_blocks (basic_blocks f (join_points f))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment