[m-rev.] diff: Refactor goal annotations in the deep profiler.

Paul Bone pbone at csse.unimelb.edu.au
Mon Jan 17 12:46:21 AEDT 2011


Refactor goal annotations in the deep profiler.

Goal annotations have previously been attached to goals using type-polymorphism
and in some cases type classes.  This has become clumsy as new annotations are
created.  Using the goal_id code introduced recently, this change associates
annotations with goals by storing them in an array indexed by goal ids.  Many
analyses have been updated to make use of this code.  This code should also be
faster as less allocation is done when annotating a goal as the goal
representation does not have to be reconstructed.

mdbcomp/mdbcomp.goal_path.m:
    Add predicates for working with goal attribute arrays.  These are
    polymorphic arrays that are indexed by goal id and can be used to associate
    information with goals.

deep_profiler/report.m:
    The procrep coverage info report now stores the coverage annotations in a
    goal_attr_array.

deep_profiler/coverage.m:
    The coverage analysis now returns its result in a goal_attr_array rather
    than by annotation the goal directly.

    The interface for the coverage module has changed, it now allows
    programmers to pass a goal_rep to it directly.  This makes it easier to
    call from other analyses.

    The coverage analysis no longer uses the calls_and_exits structure.
    Instead it uses the cost_and_callees structure like many other analyses.
    This also makes it easier to perform this annotation and others using only
    a single call site map structure.

    Moved add_coverage_point_to_map/5 from create_report.m to coverage.m.

deep_profiler/analysis_utils.m:
    Made cost_and_callees structure polymorphic so that any type can be used to
    represent the callees.  (So that either static or dynamic callees can be
    used).

    Added the number of exit port counts to the cost_and_callees structure.

    Added build_static_call_site_cost_and_callees_map/4.

    Rename build_call_site_cost_and_callees_map/4 to
    build_dynamic_call_site_cost_and_callees_map/4.

deep_profiler/var_use_analysis.m:
    Update the var_use_analysis to use coverage information provided in a
    goal_attr_array.

deep_profiler/recursion_patterns.m:
    Update the recursion analysis to use coverage information provided in a
    goal_attr_array.

deep_profiler/program_representation_utils.m:
    Add label_goals/4 to label goals with goal ids and build a map of goal ids
    to goal paths.

    Update pretty printing fucntions to work with either annotation on the
    goals themselves or provided by a higher order value.  The higher order
    argument maps nicly to the function goal_get_attribute/3 in goal_path.m

deep_profiler/mdprof_fb.automatic_parallelism.m:
    Modify goal_annotate_with_instmap, it now returns the instmap annotations
    in a goal_attr_array.

    Conform to changes in:
        program_representation_utils.m
        coverage.m
        var_use_analysis.m

deep_profiler/message.m:
    Updated messagee to more correctly express the problems that
    mdprof_fb.automatic_parallelism.m may encounter.

deep_profiler/create_report.m:
    Conform to changes in coverage.m.

    Make use of code in analysis_utils.m to prepare call site maps for coverage
    analysis.

deep_profiler/recursion_patterns.m:
deep_profiler/var_use_analysis.m:
    Conform to changes in analysis_utils.m.

deep_profiler/display_report.m:
    Conform to changes in program_representation_utils.m.

Index: deep_profiler/analysis_utils.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/analysis_utils.m,v
retrieving revision 1.7
diff -u -p -b -r1.7 analysis_utils.m
--- deep_profiler/analysis_utils.m	13 Jan 2011 04:44:28 -0000	1.7
+++ deep_profiler/analysis_utils.m	17 Jan 2011 01:31:24 -0000
@@ -50,10 +50,13 @@
 
 %----------------------------------------------------------------------------%
 
-:- type cost_and_callees
+:- type cost_and_callees == cost_and_callees(callee).
+
+:- type cost_and_callees(Callee)
     --->    cost_and_callees(
                 cac_cost            :: cs_cost_csq,
-                cac_callees         :: set(callee),
+                cac_exits           :: int,
+                cac_callees         :: set(Callee),
                 cac_call_site_is_ho :: higher_order
             ).
 
@@ -67,7 +70,12 @@
     --->    first_order_call
     ;       higher_order_call.
 
-:- pred build_call_site_cost_and_callee_map(deep::in,
+:- pred build_static_call_site_cost_and_callee_map(deep::in,
+    call_site_static_ptr::in,
+    map(reverse_goal_path, cost_and_callees(proc_static_ptr))::in,
+    map(reverse_goal_path, cost_and_callees(proc_static_ptr))::out) is det.
+
+:- pred build_dynamic_call_site_cost_and_callee_map(deep::in,
     pair(call_site_static_ptr, call_site_array_slot)::in,
     map(reverse_goal_path, cost_and_callees)::in,
     map(reverse_goal_path, cost_and_callees)::out) is det.
@@ -151,7 +159,8 @@ deep_get_maybe_procrep(Deep, PSPtr, Mayb
 
 %----------------------------------------------------------------------------%
 
-build_call_site_cost_and_callee_map(Deep, CSSPtr - Slot, !CallSitesMap) :-
+build_dynamic_call_site_cost_and_callee_map(Deep, CSSPtr - Slot,
+        !CallSitesMap) :-
     (
         Slot = slot_normal(CSDPtr),
         ( valid_call_site_dynamic_ptr(Deep, CSDPtr) ->
@@ -159,10 +168,12 @@ build_call_site_cost_and_callee_map(Deep
                 Own, Inherit),
             CostCsq = build_cs_cost_csq(calls(Own),
                 float(callseqs(Own) + inherit_callseqs(Inherit))),
-            Callees = [Callee]
+            Callees = [Callee],
+            Exits = exits(Own)
         ;
             CostCsq = build_cs_cost_csq(0, 0.0),
-            Callees = []
+            Callees = [],
+            Exits = 0
         )
     ;
         Slot = slot_multi(_, CSDPtrsArray),
@@ -172,9 +183,11 @@ build_call_site_cost_and_callee_map(Deep
         Own = sum_own_infos(Owns),
         Inherit = sum_inherit_infos(Inherits),
         CostCsq = build_cs_cost_csq(calls(Own),
-            float(callseqs(Own) + inherit_callseqs(Inherit)))
+            float(callseqs(Own) + inherit_callseqs(Inherit))),
+        Exits = exits(Own)
     ),
-    CostAndCallees = cost_and_callees(CostCsq, set(Callees), HigherOrder),
+    CostAndCallees = cost_and_callees(CostCsq, Exits, set(Callees),
+        HigherOrder),
     lookup_call_site_statics(Deep ^ call_site_statics, CSSPtr, CSS),
     call_site_kind_to_higher_order(CSS ^ css_kind, HigherOrder),
     RevGoalPath = CSS ^ css_goal_path,
@@ -209,6 +222,38 @@ call_site_kind_to_higher_order(CallSiteK
         HigherOrder = higher_order_call
     ).
 
+:- pred call_site_kind_to_maybe_callee(call_site_kind_and_callee::in,
+    maybe(proc_static_ptr)::out) is det.
+
+call_site_kind_to_maybe_callee(normal_call_and_callee(Callee, _), yes(Callee)).
+call_site_kind_to_maybe_callee(special_call_and_no_callee, no).
+call_site_kind_to_maybe_callee(higher_order_call_and_no_callee, no).
+call_site_kind_to_maybe_callee(method_call_and_no_callee, no).
+call_site_kind_to_maybe_callee(callback_and_no_callee, no).
+
+%----------------------------------------------------------------------------%
+
+build_static_call_site_cost_and_callee_map(Deep, CSSPtr, !CallSitesMap) :-
+    deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
+    deep_lookup_css_own(Deep, CSSPtr, Own),
+    deep_lookup_css_desc(Deep, CSSPtr, Inherit),
+    CostCsq = build_cs_cost_csq(calls(Own),
+        float(callseqs(Own) + inherit_callseqs(Inherit))),
+    Exits = exits(Own),
+    KindAndCallee = CSS ^ css_kind,
+    call_site_kind_to_higher_order(KindAndCallee, HigherOrder),
+    call_site_kind_to_maybe_callee(KindAndCallee, MaybeCallee),
+    (
+        MaybeCallee = yes(Callee),
+        Callees = set([Callee])
+    ;
+        MaybeCallee = no,
+        Callees = set.init
+    ),
+    CostAndCallees = cost_and_callees(CostCsq, Exits, Callees, HigherOrder),
+    RevGoalPath = CSS ^ css_goal_path,
+    svmap.det_insert(RevGoalPath, CostAndCallees, !CallSitesMap).
+
 %----------------------------------------------------------------------------%
 
 build_recursive_call_site_cost_map(Deep, CliquePtr, PDPtr, RecursionType,
Index: deep_profiler/coverage.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/coverage.m,v
retrieving revision 1.13
diff -u -p -b -r1.13 coverage.m
--- deep_profiler/coverage.m	13 Jan 2011 04:44:28 -0000	1.13
+++ deep_profiler/coverage.m	17 Jan 2011 01:31:24 -0000
@@ -17,6 +17,7 @@
 
 :- interface.
 
+:- import_module analysis_utils.
 :- import_module mdbcomp.
 :- import_module mdbcomp.goal_path.
 :- import_module mdbcomp.program_representation.
@@ -25,7 +26,6 @@
 :- import_module array.
 :- import_module list.
 :- import_module map.
-:- import_module maybe.
 
 :- type coverage_info
     --->    coverage_unknown
@@ -82,32 +82,47 @@
 
 %----------------------------------------------------------------------------%
 
-    % The coverage of a call site can be expressed as the number of calls and
-    % exits at that call site.
+    % Annotate the program representation structure with coverage information.
     %
-:- type calls_and_exits
-    --->    calls_and_exits(
-                cae_calls           :: int,
-                cae_exits           :: int
-            ).
+:- pred procrep_annotate_with_coverage(proc_rep(goal_id)::in,
+    own_prof_info::in,
+    map(reverse_goal_path, cost_and_callees(T))::in,
+    map(reverse_goal_path, coverage_point)::in,
+    map(reverse_goal_path, coverage_point)::in,
+    containing_goal_map::in, goal_id::in,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
 
-    % Annotate the program representation structure with coverage information.
+:- pred goal_annotate_with_coverage(string_proc_label::in,
+    goal_rep(goal_id)::in, own_prof_info::in,
+    map(reverse_goal_path, cost_and_callees(T))::in,
+    map(reverse_goal_path, coverage_point)::in,
+    map(reverse_goal_path, coverage_point)::in,
+    containing_goal_map::in, goal_id::in,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+    % foldl(add_coverage_point, CoveragePoints, map.init, SolnsCPs,
+    %   map.init, BranchCPs),
     %
-:- pred procrep_annotate_with_coverage(own_prof_info::in,
-    map(reverse_goal_path, calls_and_exits)::in,
+:- pred add_coverage_point_to_map(coverage_point::in,
     map(reverse_goal_path, coverage_point)::in,
+    map(reverse_goal_path, coverage_point)::out,
     map(reverse_goal_path, coverage_point)::in,
-    proc_rep::in, maybe_error(proc_rep(coverage_info))::out) is det.
+    map(reverse_goal_path, coverage_point)::out) is det.
 
 %-----------------------------------------------------------------------------%
 
 :- implementation.
 
 :- import_module bool.
+:- import_module float.
 :- import_module int.
 :- import_module io.
+:- import_module maybe.
 :- import_module require.
 :- import_module string.
+:- import_module svmap.
 :- import_module unit.
 
 %-----------------------------------------------------------------------------%
@@ -217,26 +232,30 @@ coverage_point_arrays_to_list_2(Num, Max
     %       algorithm to proceed past the problem and allow the programmer to
     %       view erroneous output.
     %
-procrep_annotate_with_coverage(OwnProf, CallSites, SolnsCoveragePoints,
-        BranchCoveragePoints, !.ProcRep, MaybeProcRep) :-
-    some [!ProcDefn, !GoalRep] (
-        !:ProcDefn = !.ProcRep ^ pr_defn,
-        !:GoalRep = !.ProcDefn ^ pdr_goal,
-        ProcLabel = !.ProcRep ^ pr_id,
+procrep_annotate_with_coverage(ProcRep, OwnProf, CallSites, SolnsCoveragePoints,
+        BranchCoveragePoints, ContainingGoalMap, LastGoalId, CoverageArray) :-
+    GoalRep = ProcRep ^ pr_defn ^ pdr_goal,
+    ProcLabel = ProcRep ^ pr_id,
+    goal_annotate_with_coverage(ProcLabel, GoalRep, OwnProf,
+        CallSites, SolnsCoveragePoints, BranchCoveragePoints,
+        ContainingGoalMap, LastGoalId, CoverageArray).
+
+goal_annotate_with_coverage(ProcLabel, GoalRep, OwnProf, CallSites,
+        SolnsCoveragePoints, BranchCoveragePoints, ContainingGoalMap,
+        LastGoalId, CoverageArray) :-
         Calls = calls(OwnProf),
         Exits = exits(OwnProf),
         Before = before_coverage(Calls),
+    GoalPathMap = create_reverse_goal_path_map(ContainingGoalMap),
         CoverageReference = coverage_reference_info(ProcLabel, CallSites,
-            SolnsCoveragePoints, BranchCoveragePoints),
-        goal_annotate_coverage(CoverageReference, [],
-            Before, After, !GoalRep),
+        SolnsCoveragePoints, BranchCoveragePoints, GoalPathMap),
+    CoverageArray0 = create_goal_id_array(LastGoalId),
+    goal_annotate_coverage(GoalRep, CoverageReference,
+        Before, After, CoverageArray0, CoverageArray),
         require(unify(After, after_coverage(Exits)),
             "Coverage after procedure not equal with exit count of" ++
-            " procedure"),
-        !:ProcDefn = !.ProcDefn ^ pdr_goal := !.GoalRep,
-        !:ProcRep = !.ProcRep ^ pr_defn := !.ProcDefn,
-        MaybeProcRep = ok(!.ProcRep)
-    ).
+        " procedure").
+
 
     % These maps are keyed by reverse_goal_path, comparing these structures
     % is less efficient than comparing simple structures like the alternative
@@ -244,81 +263,82 @@ procrep_annotate_with_coverage(OwnProf, 
     % from goal paths.  Using reverse_goal_path_string may be faster but
     % I'd rather not make this optimisation without first testing it.
     %
-:- type coverage_reference_info
+:- type coverage_reference_info(Callee)
     --->    coverage_reference_info(
                 cri_proc        :: string_proc_label,
-                cri_call_sites  :: map(reverse_goal_path, calls_and_exits),
+                cri_call_sites  ::
+                    map(reverse_goal_path, cost_and_callees(Callee)),
                 cri_solns_coverage_points
                                 :: map(reverse_goal_path, coverage_point),
                 cri_branch_coverage_points
-                                :: map(reverse_goal_path, coverage_point)
+                                :: map(reverse_goal_path, coverage_point),
+                cri_goal_path_map
+                                :: goal_reverse_path_map
             ).
 
     % Annotate a goal and its children with coverage information.
     %
-:- pred goal_annotate_coverage(coverage_reference_info::in,
-    list(goal_path_step)::in, coverage_before::in, coverage_after::out,
-    goal_rep(unit)::in, goal_rep(coverage_info)::out) is det.
+:- pred goal_annotate_coverage(goal_rep(goal_id)::in,
+    coverage_reference_info(Callee)::in,
+    coverage_before::in, coverage_after::out,
+    goal_attr_array(coverage_info)::gaa_di,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
 
-goal_annotate_coverage(Info, RevGoalPathSteps, Before, After, Goal0, Goal) :-
-    Goal0 = goal_rep(GoalExpr0, Detism, _),
+goal_annotate_coverage(Goal, Info, Before, After, !Array) :-
+    Goal = goal_rep(GoalExpr, Detism, GoalId),
+    RevGoalPath = map.lookup(Info ^ cri_goal_path_map, GoalId),
 
     % Calculate coverage of any inner goals.
     (
-        GoalExpr0 = conj_rep(Conjuncts0),
-        conj_annotate_coverage(Info, RevGoalPathSteps,
-            Before, After0, Conjuncts0, Conjuncts),
-        GoalExpr = conj_rep(Conjuncts)
-    ;
-        GoalExpr0 = disj_rep(Disjuncts0),
-        disj_annotate_coverage(Info, Detism, RevGoalPathSteps,
-            Before, After0, Disjuncts0, Disjuncts),
-        GoalExpr = disj_rep(Disjuncts)
-    ;
-        GoalExpr0 = switch_rep(Var, CanFail, Cases0),
-        switch_annotate_coverage(Info, CanFail, RevGoalPathSteps,
-            Before, After0, Cases0, Cases),
-        GoalExpr = switch_rep(Var, CanFail, Cases)
-    ;
-        GoalExpr0 = ite_rep(Cond0, Then0, Else0),
-        ite_annotate_coverage(Info, RevGoalPathSteps,
-            Before, After0, Cond0, Cond, Then0, Then, Else0, Else),
-        GoalExpr = ite_rep(Cond, Then, Else)
-    ;
-        GoalExpr0 = negation_rep(NegGoal0),
-        negation_annotate_coverage(Info, RevGoalPathSteps,
-            Before, After0, NegGoal0, NegGoal),
-        GoalExpr = negation_rep(NegGoal)
-    ;
-        GoalExpr0 = scope_rep(ScopedGoal0, MaybeCut),
-        scope_annotate_coverage(Info, RevGoalPathSteps, MaybeCut,
-            Before, After0, ScopedGoal0, ScopedGoal),
-        GoalExpr = scope_rep(ScopedGoal, MaybeCut)
-    ;
-        GoalExpr0 = atomic_goal_rep(Filename, Line, Vars, AtomicGoal),
-        % Note that GoalExpr != GoalExpr0, since they are of different types.
-        GoalExpr = atomic_goal_rep(Filename, Line, Vars, AtomicGoal),
+        GoalExpr = conj_rep(Conjs),
+        conj_annotate_coverage(Conjs, Info, Before, After0, !Array)
+    ;
+        GoalExpr = disj_rep(Disjs),
+        Solutions = detism_get_solutions(Detism),
+        % Note: In theory, we could update Before using information from any
+        % counter at the start of the first disjunct, but we don't do that
+        % (yet).  This may not be useful for some disjunctions, for example
+        % those called from a single solution context or committed-choice.
+        disj_annotate_coverage(Disjs, Info, Solutions,
+            Before, sum_after_zero, SumAfterDisjuncts, !Array),
+        after_count_sum_after_count(SumAfterDisjuncts, After0)
+    ;
+        GoalExpr = switch_rep(_Var, CanFail, Cases),
+        switch_annotate_coverage(Cases, Info, CanFail, Before, After0, !Array)
+    ;
+        GoalExpr = ite_rep(Cond, Then, Else),
+        ite_annotate_coverage(Cond, Then, Else, Info, RevGoalPath,
+            Before, After0, !Array)
+    ;
+        GoalExpr = negation_rep(NegGoal),
+        negation_annotate_coverage(NegGoal, Info, Before, After0, !Array)
+    ;
+        GoalExpr = scope_rep(ScopedGoal, MaybeCut),
+        scope_annotate_coverage(ScopedGoal, Info, MaybeCut, Before, After0,
+            !Array)
+    ;
+        GoalExpr = atomic_goal_rep(_, _, _, AtomicGoal),
         (
             ( AtomicGoal = plain_call_rep(_, _, _)
             ; AtomicGoal = higher_order_call_rep(_, _)
             ; AtomicGoal = method_call_rep(_, _, _)
             ),
             (
-                map.search(Info ^ cri_call_sites, rgp(RevGoalPathSteps),
-                    CallsAndExits)
+                map.search(Info ^ cri_call_sites, RevGoalPath, Cost)
             ->
                 % Entry due to redo is not counted at the point before the
                 % goal, it is represented when the number of exists is greater
                 % than the number of calls. XXX This won't work with nondet
                 % code, which should be fixed in the future.
-                CallsAndExits = calls_and_exits(Calls, Exits),
+                Calls = round_to_int(cs_cost_get_calls(Cost ^ cac_cost)),
+                Exits = Cost ^ cac_exits,
                 require(unify(Before, before_coverage(Calls)),
                   "Coverage before call doesn't match calls port on call site"),
                 After0 = after_coverage(Exits)
             ;
                 unexpected($module, $pred,
                     "Couldn't look up call site for port counts GP: " ++
-                    rev_goal_path_to_string(rgp(RevGoalPathSteps)))
+                    rev_goal_path_to_string(RevGoalPath))
             )
         ;
             ( AtomicGoal = builtin_call_rep(_, _, _)
@@ -341,7 +361,7 @@ goal_annotate_coverage(Info, RevGoalPath
     % is used to perform an assertion that these two sources agree about the
     % coverage after this goal.
     (
-        map.search(Info ^ cri_solns_coverage_points, rgp(RevGoalPathSteps),
+        map.search(Info ^ cri_solns_coverage_points, RevGoalPath,
             CoveragePoint)
     ->
         CoveragePoint = coverage_point(CoverageAfterCount, _, _),
@@ -351,12 +371,12 @@ goal_annotate_coverage(Info, RevGoalPath
         After0 = After
     ),
     GoalCoverage = construct_before_after_coverage(Before, After),
-    Goal = goal_rep(GoalExpr, Detism, GoalCoverage),
+    update_goal_attribute(GoalId, GoalCoverage, !Array),
 
     trace [compile_time(flag("debug_coverage_propagation")), io(!IO)] (
         io.write_string("goal_annotate_coverage: done\n", !IO),
         io.format("\tGoalPath: %s\n\tDetism %s\n\tCoverage; %s\n",
-            [s(rev_goal_path_to_string(rgp(RevGoalPathSteps))),
+            [s(rev_goal_path_to_string(RevGoalPath)),
              s(string(Detism)),
              s(string(GoalCoverage))], !IO)
     ),
@@ -368,7 +388,7 @@ goal_annotate_coverage(Info, RevGoalPath
                 string.format("check_coverage_complete failed\n" ++
                     "\tCoverage: %s\n\tGoalPath: %s\n\tProc: %s\n",
                     [s(string(GoalCoverage)),
-                     s(rev_goal_path_to_string(rgp(RevGoalPathSteps))),
+                     s(rev_goal_path_to_string(RevGoalPath)),
                      s(string(Info ^ cri_proc))]))
         ),
         ( check_coverage_regarding_detism(GoalCoverage, Detism) ->
@@ -428,36 +448,23 @@ construct_before_after_coverage(Before, 
 
     % Annotate a conjunction with coverage information.
     %
-:- pred conj_annotate_coverage(coverage_reference_info::in,
-    list(goal_path_step)::in, coverage_before::in, coverage_after::out,
-    list(goal_rep(unit))::in, list(goal_rep(coverage_info))::out) is det.
-
-conj_annotate_coverage(Info, RevGoalPathSteps, Before, After, Conjs0, Conjs) :-
-    conj_annotate_coverage_2(Info, RevGoalPathSteps, 1, Before, After,
-        Conjs0, Conjs).
-
-    % Annotate a conjunction with coverage information.
-    %
     % The list of goals is the tail of a conjunction, the coverage argument
     % describes the coverage of this list of goals if it were the entire
     % conjunction.  Each goal also has it's own coverage.
     %
-:- pred conj_annotate_coverage_2(coverage_reference_info::in,
-    list(goal_path_step)::in, int::in,
+:- pred conj_annotate_coverage(list(goal_rep(goal_id))::in,
+    coverage_reference_info(Callee)::in,
     coverage_before::in, coverage_after::out,
-    list(goal_rep(unit))::in, list(goal_rep(coverage_info))::out) is det.
+    goal_attr_array(coverage_info)::gaa_di,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
 
-conj_annotate_coverage_2(_, _, _, Before, After, [], []) :-
+conj_annotate_coverage([], _, Before, After, !Array) :-
     % The empty conjunction is equivalent to 'true' which is deterministic,
     propagate_det_coverage(Before, After).
-conj_annotate_coverage_2(Info, RevGoalPathSteps, ConjunctNum, Before, After,
-        [Conj0 | Conjs0], [Conj | Conjs]) :-
-    RevSubGoalPathStep = [step_conj(ConjunctNum) | RevGoalPathSteps],
-    goal_annotate_coverage(Info, RevSubGoalPathStep,
-        Before, CoverageAfterHead, Conj0, Conj),
+conj_annotate_coverage([Conj | Conjs], Info, Before, After, !Array) :-
+    goal_annotate_coverage(Conj, Info, Before, CoverageAfterHead, !Array),
     after_to_before_coverage(CoverageAfterHead, CoverageBeforeTail),
-    conj_annotate_coverage_2(Info, RevGoalPathSteps, ConjunctNum + 1,
-        CoverageBeforeTail, After, Conjs0, Conjs).
+    conj_annotate_coverage(Conjs, Info, CoverageBeforeTail, After, !Array).
 
     % Compute the coverage information for a disjunction.
     %
@@ -467,30 +474,17 @@ conj_annotate_coverage_2(Info, RevGoalPa
     %   - The coverage after a disjunction is equal to the sum of coverages
     %     after each disjunct.
     %
-:- pred disj_annotate_coverage(coverage_reference_info::in, detism_rep::in,
-    list(goal_path_step)::in, coverage_before::in, coverage_after::out,
-    list(goal_rep(unit))::in, list(goal_rep(coverage_info))::out) is det.
-
-disj_annotate_coverage(Info, Detism, RevGoalPathSteps, Before, After,
-        Disjs0, Disjs) :-
-    % XXX In theory, we could update Before using information from any counter
-    % at the start of the first disjunct, but we don't do that (yet).  This may
-    % not be useful for some disjunctions, for example those called from a
-    % single solution context or committed-choice.
-    Solutions = detism_get_solutions(Detism),
-    disj_annotate_coverage_2(Info, RevGoalPathSteps, 1, Solutions,
-        Before, sum_after_zero, SumAfterDisjuncts, Disjs0, Disjs),
-    after_count_sum_after_count(SumAfterDisjuncts, After).
-
-:- pred disj_annotate_coverage_2(coverage_reference_info::in,
-    list(goal_path_step)::in, int::in, solution_count_rep::in,
+:- pred disj_annotate_coverage(list(goal_rep(goal_id))::in,
+    coverage_reference_info(Callee)::in, solution_count_rep::in,
     coverage_before::in, sum_coverage_after::in, sum_coverage_after::out,
-    list(goal_rep)::in, list(goal_rep(coverage_info))::out) is det.
+    goal_attr_array(coverage_info)::gaa_di,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
 
-disj_annotate_coverage_2(_, _, _, _, _, !SumAfter, [], []).
-disj_annotate_coverage_2(Info, RevGoalPathSteps, DisjNum, Solutions,
-        Before0, !SumAfter, [Disj0 | Disjs0], [Disj | Disjs]) :-
-    RevSubGoalPathSteps = [step_disj(DisjNum) | RevGoalPathSteps],
+disj_annotate_coverage([], _, _, _, !SumAfter, !Array).
+disj_annotate_coverage([Disj | Disjs], Info, Solutions, Before0, !SumAfter,
+        !Array) :-
+    DisjRevGoalPath =
+        map.lookup(Info ^ cri_goal_path_map, Disj ^ goal_annotation),
     (
         ( Before0 = before_known(_)
         ; Before0 = before_zero
@@ -498,30 +492,28 @@ disj_annotate_coverage_2(Info, RevGoalPa
         Before = Before0
     ;
         Before0 = before_unknown,
-        get_branch_start_coverage(Info, rgp(RevSubGoalPathSteps), Before)
+        get_branch_start_coverage(Info, DisjRevGoalPath, Before)
     ),
-    goal_annotate_coverage(Info, RevSubGoalPathSteps,
-        Before, After, Disj0, Disj),
+    goal_annotate_coverage(Disj, Info, Before, After, !Array),
     sum_after_coverage(After, !SumAfter),
     % We don't know how many times the start of the next disjunct is executed
     % unless we have a counter there.
-    disj_annotate_coverage_2(Info, RevGoalPathSteps, DisjNum + 1, Solutions,
-        before_unknown, !SumAfter, Disjs0, Disjs).
+    disj_annotate_coverage(Disjs, Info, Solutions, before_unknown, !SumAfter,
+        !Array).
 
-:- pred switch_annotate_coverage(coverage_reference_info::in,
-    switch_can_fail_rep::in, list(goal_path_step)::in,
+:- pred switch_annotate_coverage(list(case_rep(goal_id))::in,
+    coverage_reference_info(Callee)::in, switch_can_fail_rep::in,
     coverage_before::in, coverage_after::out,
-    list(case_rep(unit))::in, list(case_rep(coverage_info))::out) is det.
+    goal_attr_array(coverage_info)::gaa_di,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
 
-switch_annotate_coverage(Info, CanFail, RevGoalPathSteps, Before, After,
-        Cases0, Cases) :-
+switch_annotate_coverage(Cases, Info, CanFail, Before, After, !Array) :-
     trace [compile_time(flag("debug_coverage_propagation")), io(!IO)] (
         io.format("Switch: Before0: %s\n", [s(string(Before))], !IO)
     ),
 
-    switch_annotate_coverage_2(Info, CanFail, RevGoalPathSteps, 1,
-        sum_before_zero, _SumBefore, sum_after_zero, SumAfter,
-        Before, Cases0, Cases),
+    switch_annotate_coverage_2(Cases, Info, CanFail, Before,
+        sum_before_zero, _SumBefore, sum_after_zero, SumAfter, !Array),
     % For can_fail switches, the sum of the exec counts at the starts of the
     % arms may be less than the exec count at the start of the switch. However,
     % even for can_fail switches, the sum of the exec counts at the *ends* of
@@ -539,9 +531,11 @@ switch_annotate_coverage(Info, CanFail, 
     %),
 
     trace [compile_time(not flag("no_coverage_propagation_assertions"))] (
-        ( check_switch_coverage(CanFail, Cases, Before) ->
-            true
+        check_switch_coverage(CanFail, Cases, Before, !.Array, Result),
+        (
+            Result = yes
         ;
+            Result = no,
             error(string.format("check_switch_coverage failed\n\t" ++
                 "CanFail: %s\n\tCases: %s\n\tBefore: %s, After: %s\n",
                 [s(string(CanFail)), s(string(Cases)),
@@ -562,19 +556,16 @@ switch_annotate_coverage(Info, CanFail, 
     % the end of the last goal may need to be computed from the coverage of
     % each of the other goals.
     %
-:- pred switch_annotate_coverage_2(coverage_reference_info::in,
-    switch_can_fail_rep::in, list(goal_path_step)::in, int::in,
-    sum_coverage_before::in, sum_coverage_before::out,
+:- pred switch_annotate_coverage_2(list(case_rep(goal_id))::in,
+    coverage_reference_info(Callee)::in, switch_can_fail_rep::in,
+    coverage_before::in, sum_coverage_before::in, sum_coverage_before::out,
     sum_coverage_after::in, sum_coverage_after::out,
-    coverage_before::in,
-    list(case_rep(unit))::in, list(case_rep(coverage_info))::out) is det.
-
-switch_annotate_coverage_2(_, _, _, _, !SumBefore, !SumAfter, _, [], []).
-switch_annotate_coverage_2(Info, CanFail, RevGoalPathSteps, CaseNum,
-        !SumBefore, !SumAfter, SwitchBefore,
-        [Case0 | Cases0], [Case | Cases]) :-
-    RevSubGoalPathSteps = [step_switch(CaseNum, no) | RevGoalPathSteps],
+    goal_attr_array(coverage_info)::gaa_di,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
 
+switch_annotate_coverage_2([], _, _, _, !SumBefore, !SumAfter, !Array).
+switch_annotate_coverage_2([Case | Cases], Info, CanFail, SwitchBefore,
+        !SumBefore, !SumAfter, !Array) :-
     % If this is the last case in the switch, then its coverage information
     % may be computed from the coverage of other cases and the coverage of the
     % whole switch.  This is only done for the last goal, since only this
@@ -583,7 +574,7 @@ switch_annotate_coverage_2(Info, CanFail
     % If we cannot calculate this case's coverage information, then try to
     % retrieve the information from a coverage point associated with the case.
     (
-        Cases0 = [],
+        Cases = [],
         CanFail = switch_can_not_fail_rep,
         (
             SwitchBefore = before_known(SwitchBeforeExecCount)
@@ -601,41 +592,37 @@ switch_annotate_coverage_2(Info, CanFail
         BeforeCase = before_coverage(SwitchBeforeExecCount - SumBeforeExecCount)
     ;
         % Search for a coverage point for this case.
-        get_branch_start_coverage(Info, rgp(RevSubGoalPathSteps), BeforeCase)
+        RevCaseGoalPath = map.lookup(Info ^ cri_goal_path_map,
+            Goal ^ goal_annotation),
+        get_branch_start_coverage(Info, RevCaseGoalPath, BeforeCase)
     ),
 
     % Calculate and annotate the coverage for the case itself.
-    Case0 = case_rep(ConsID, OtherConsIDs, Goal0),
-    goal_annotate_coverage(Info, RevSubGoalPathSteps,
-        BeforeCase, AfterCase, Goal0, Goal),
-    Case = case_rep(ConsID, OtherConsIDs, Goal),
+    Case = case_rep(_ConsID, _OtherConsIDs, Goal),
+    goal_annotate_coverage(Goal, Info, BeforeCase, AfterCase, !Array),
 
     % Keep a sum of the execution counts seen in cases so far.
     sum_before_coverage(BeforeCase, !SumBefore),
     sum_after_coverage(AfterCase, !SumAfter),
 
-    switch_annotate_coverage_2(Info, CanFail, RevGoalPathSteps, CaseNum + 1,
-        !SumBefore, !SumAfter, SwitchBefore, Cases0, Cases).
+    switch_annotate_coverage_2(Cases, Info, CanFail, SwitchBefore,
+        !SumBefore, !SumAfter, !Array).
 
     % Propagate coverage information for if-then-else goals.
     %
-:- pred ite_annotate_coverage(coverage_reference_info::in,
-    list(goal_path_step)::in, coverage_before::in, coverage_after::out,
-    goal_rep::in, goal_rep(coverage_info)::out,
-    goal_rep::in, goal_rep(coverage_info)::out,
-    goal_rep::in, goal_rep(coverage_info)::out) is det.
-
-ite_annotate_coverage(Info, RevGoalPathSteps, Before, After,
-        Cond0, Cond, Then0, Then, Else0, Else) :-
-    RevCondGoalPathSteps = [step_ite_cond | RevGoalPathSteps],
-    RevThenGoalPathSteps = [step_ite_then | RevGoalPathSteps],
-    RevElseGoalPathSteps = [step_ite_else | RevGoalPathSteps],
-    CondDetism = Cond0 ^ goal_detism_rep,
+:- pred ite_annotate_coverage(goal_rep(goal_id)::in, goal_rep(goal_id)::in,
+    goal_rep(goal_id)::in, coverage_reference_info(Callee)::in,
+    reverse_goal_path::in, coverage_before::in, coverage_after::out,
+    goal_attr_array(coverage_info)::gaa_di,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
+
+ite_annotate_coverage(Cond, Then, Else, Info, RevGoalPath, Before, After, !Array) :-
+    CondDetism = Cond ^ goal_detism_rep,
+    GoalPathMap = Info ^ cri_goal_path_map,
 
     % Step 1:
     %   Call goal_annotate_coverage for the condition goal.
-    goal_annotate_coverage(Info, RevCondGoalPathSteps,
-        Before, AfterCond, Cond0, Cond),
+    goal_annotate_coverage(Cond, Info, Before, AfterCond, !Array),
     after_to_before_coverage(AfterCond, BeforeThen0),
 
     % Step 2:
@@ -647,7 +634,8 @@ ite_annotate_coverage(Info, RevGoalPathS
         BeforeThen = BeforeThen0
     ;
         BeforeThen0 = before_unknown,
-        get_branch_start_coverage(Info, rgp(RevThenGoalPathSteps), BeforeThen)
+        RevThenGoalPath = map.lookup(GoalPathMap, Then ^ goal_annotation),
+        get_branch_start_coverage(Info, RevThenGoalPath, BeforeThen)
     ),
     % XXX It should be possible, if the condition is not at_most_many and does
     % not throw exceptions, to compute BeforeElse as the difference between the
@@ -655,22 +643,21 @@ ite_annotate_coverage(Info, RevGoalPathS
     % check_ite_coverage already knows the relationship.  Using exception
     % counts on call goals and propagating them through the coverage annotation
     % algorithms can solve this.
-    get_branch_start_coverage(Info, rgp(RevElseGoalPathSteps), BeforeElse),
+    RevElseGoalPath = map.lookup(GoalPathMap, Else ^ goal_annotation),
+    get_branch_start_coverage(Info, RevElseGoalPath, BeforeElse),
 
     trace [compile_time(flag("debug_coverage_propagation")), io(!IO)] (
         io.format("ITE Coverage inferred before then and else branches:\n" ++
             "\tWhole: %s \n\tThen: %s\n\tElse: %s\n" ++
             "\tGoalPath %s\n",
             [s(string(Before)), s(string(BeforeThen)), s(string(BeforeElse)),
-            s(rev_goal_path_to_string(rgp(RevGoalPathSteps)))], !IO)
+            s(rev_goal_path_to_string(RevGoalPath))], !IO)
     ),
 
     % Step 3:
     %   Call goal_annotate_coverage for the then and else goals.
-    goal_annotate_coverage(Info, RevThenGoalPathSteps,
-        BeforeThen, AfterThen, Then0, Then),
-    goal_annotate_coverage(Info, RevElseGoalPathSteps,
-        BeforeElse, AfterElse, Else0, Else),
+    goal_annotate_coverage(Then, Info, BeforeThen, AfterThen, !Array),
+    goal_annotate_coverage(Else, Info, BeforeElse, AfterElse, !Array),
 
     % Step 4:
     %   Update what we know about the if-then-else as a whole.
@@ -718,14 +705,14 @@ ite_annotate_coverage(Info, RevGoalPathS
                 s(string(Before)), s(string(AfterCond)),
                 s(string(BeforeThen)), s(string(AfterThen)),
                 s(string(BeforeElse)), s(string(AfterElse)),
-                s(rev_goal_path_to_string(rgp(RevGoalPathSteps)))]))
+                s(rev_goal_path_to_string(RevGoalPath))]))
         )
     ).
 
     % Get the coverage information from a coverage point about the branch
     % referenced by the given goal path.
     %
-:- pred get_branch_start_coverage(coverage_reference_info::in,
+:- pred get_branch_start_coverage(coverage_reference_info(Callee)::in,
     reverse_goal_path::in, coverage_before::out) is det.
 
 get_branch_start_coverage(Info, RevGoalPath, Before) :-
@@ -736,15 +723,14 @@ get_branch_start_coverage(Info, RevGoalP
         Before = before_unknown
     ).
 
-:- pred negation_annotate_coverage(coverage_reference_info::in,
-    list(goal_path_step)::in, coverage_before::in, coverage_after::out,
-    goal_rep::in, goal_rep(coverage_info)::out) is det.
-
-negation_annotate_coverage(Info, RevGoalPathSteps, Before, After,
-        NegGoal0, NegGoal) :-
-    RevSubGoalPathSteps = [step_neg | RevGoalPathSteps],
-    goal_annotate_coverage(Info, RevSubGoalPathSteps,
-        Before, _CoverageAfter, NegGoal0, NegGoal),
+:- pred negation_annotate_coverage(goal_rep(goal_id)::in,
+    coverage_reference_info(Callee)::in,
+    coverage_before::in, coverage_after::out,
+    goal_attr_array(coverage_info)::gaa_di,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
+
+negation_annotate_coverage(Goal, Info, Before, After, !Array) :-
+    goal_annotate_coverage(Goal, Info, Before, _CoverageAfter, !Array),
     % The coverage after a negation is always unknown.
     After = after_unknown,
     trace [compile_time(flag("debug_coverage_propagation")), io(!IO)] (
@@ -752,16 +738,14 @@ negation_annotate_coverage(Info, RevGoal
             [s(string(Before)), s(string(After))], !IO)
     ).
 
-:- pred scope_annotate_coverage(coverage_reference_info::in,
-    list(goal_path_step)::in, maybe_cut::in,
+:- pred scope_annotate_coverage(goal_rep(goal_id)::in,
+    coverage_reference_info(Callee)::in, maybe_cut::in,
     coverage_before::in, coverage_after::out,
-    goal_rep::in, goal_rep(coverage_info)::out) is det.
+    goal_attr_array(coverage_info)::gaa_di,
+    goal_attr_array(coverage_info)::gaa_uo) is det.
 
-scope_annotate_coverage(Info, RevGoalPathSteps, MaybeCut, Before, After,
-        ScopedGoal0, ScopedGoal) :-
-    RevSubGoalPathSteps = [step_scope(MaybeCut) | RevGoalPathSteps],
-    goal_annotate_coverage(Info, RevSubGoalPathSteps,
-        Before, AfterScopedGoal, ScopedGoal0, ScopedGoal),
+scope_annotate_coverage(Goal, Info, MaybeCut, Before, After, !Array) :-
+    goal_annotate_coverage(Goal, Info, Before, AfterScopedGoal, !Array),
     (
         MaybeCut = scope_is_cut,
         After = after_unknown
@@ -886,38 +870,49 @@ detism_coverage_ok(Coverage, Detism) = O
     % contradict with each other.  This works only for cannot_fail switches.
     %
 :- pred check_switch_coverage(switch_can_fail_rep::in,
-    list(case_rep(coverage_info))::in, coverage_before::in) is semidet.
+    list(case_rep(goal_id))::in, coverage_before::in,
+    goal_attr_array(coverage_info)::in, bool::out) is det.
 
-check_switch_coverage(CanFail, Cases, Before) :-
+check_switch_coverage(CanFail, Cases, Before, Array, Result) :-
     (
         CanFail = switch_can_not_fail_rep,
-        list.foldl(sum_switch_case_coverage, Cases, yes(0), MaybeSum),
+        list.foldl(sum_switch_case_coverage(Array), Cases, yes(0), MaybeSum),
         (
-            MaybeSum = yes(Sum),
+            MaybeSum = yes(SumA),
             (
                 (
-                    Before = before_known(Sum)
+                    Before = before_unknown,
+                    Result = yes
                 ;
-                    Before = before_unknown
+                    (
+                        Before = before_known(SumB)
                 ;
                     Before = before_zero,
-                    Sum = 0
+                        SumB = 0
+                    ),
+                    ( SumA = SumB ->
+                        Result = yes
+                    ;
+                        Result = no
+                    )
                 )
             )
         ;
-            MaybeSum = no
+            MaybeSum = no,
+            Result = yes
         )
     ;
-        CanFail = switch_can_fail_rep
+        CanFail = switch_can_fail_rep,
+        Result = yes
     ).
 
-:- pred sum_switch_case_coverage(case_rep(coverage_info)::in,
-    maybe(int)::in, maybe(int)::out) is det.
+:- pred sum_switch_case_coverage(goal_attr_array(coverage_info)::in,
+    case_rep(goal_id)::in, maybe(int)::in, maybe(int)::out) is det.
 
-sum_switch_case_coverage(case_rep(_, _, Goal), !Acc) :-
+sum_switch_case_coverage(Array, case_rep(_, _, Goal), !Acc) :-
     (
         !.Acc = yes(Count),
-        Coverage = Goal ^ goal_annotation,
+        Coverage = get_goal_attribute_det(Array, Goal ^ goal_annotation),
         (
             ( Coverage = coverage_known_same(Addend)
             ; Coverage = coverage_known(Addend, _)
@@ -1277,8 +1272,15 @@ before_coverage(Count) =
 
 %----------------------------------------------------------------------------%
 
-:- func this_file = string.
-
-this_file = "coverage.m: ".
+add_coverage_point_to_map(CoveragePoint, !SolnsMap, !BranchMap) :-
+    CoveragePoint = coverage_point(_, GoalPath, CPType),
+    (
+        CPType = cp_type_coverage_after,
+        svmap.det_insert(GoalPath, CoveragePoint, !SolnsMap)
+    ;
+        CPType = cp_type_branch_arm,
+        svmap.det_insert(GoalPath, CoveragePoint, !BranchMap)
+    ).
 
 %----------------------------------------------------------------------------%
+%----------------------------------------------------------------------------%
Index: deep_profiler/create_report.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/create_report.m,v
retrieving revision 1.32
diff -u -p -b -r1.32 create_report.m
--- deep_profiler/create_report.m	13 Jan 2011 00:36:55 -0000	1.32
+++ deep_profiler/create_report.m	17 Jan 2011 01:31:24 -0000
@@ -89,6 +89,7 @@
 :- import_module mdbcomp.goal_path.
 :- import_module mdbcomp.program_representation.
 :- import_module measurement_units.
+:- import_module program_representation_utils.
 :- import_module recursion_patterns.
 :- import_module top_procs.
 :- import_module var_use_analysis.
@@ -1111,8 +1112,8 @@ create_static_procrep_coverage_report(De
         % Gather call site information.
         deep_lookup_proc_statics(Deep, PSPtr, PS),
         CallSitesArray = PS ^ ps_sites,
-        CallSitesMap = array.foldl(add_ps_calls_and_exits_to_map(Deep),
-            CallSitesArray, map.init),
+        array.foldl(build_static_call_site_cost_and_callee_map(Deep),
+            CallSitesArray, map.init, CallSitesMap),
 
         % Gather information about the procedure.
         deep_lookup_ps_own(Deep, PSPtr, Own),
@@ -1132,12 +1133,8 @@ create_dynamic_procrep_coverage_report(D
         MaybeCoveragePoints = PD ^ pd_maybe_coverage_points,
 
         % Gather call site information.
-        deep_lookup_proc_statics(Deep, PSPtr, PS),
-        StaticCallSitesArray = PS ^ ps_sites,
-        DynamicCallSitesArray = PD ^ pd_sites,
-        foldl_corresponding(
-            add_pd_calls_and_exits_to_map(Deep),
-            to_list(StaticCallSitesArray), to_list(DynamicCallSitesArray),
+        proc_dynamic_paired_call_site_slots(Deep, PDPtr, Slots),
+        foldl(build_dynamic_call_site_cost_and_callee_map(Deep), Slots, 
             map.init, CallSitesMap),
 
         % Gather information about the procedure.
@@ -1153,7 +1150,7 @@ create_dynamic_procrep_coverage_report(D
 
 :- pred maybe_create_procrep_coverage_report(deep::in, proc_static_ptr::in,
     own_prof_info::in, maybe(array(int))::in,
-    map(reverse_goal_path, calls_and_exits)::in,
+    map(reverse_goal_path, cost_and_callees(Callee))::in,
     maybe_error(procrep_coverage_info)::out) is det.
 
 maybe_create_procrep_coverage_report(_, _, _, no, _, error(Error)) :-
@@ -1173,84 +1170,13 @@ maybe_create_procrep_coverage_report(Dee
         foldl2(add_coverage_point_to_map,
             CoveragePoints, map.init, SolnsCoveragePointMap,
             map.init, BranchCoveragePointMap),
-
-        procrep_annotate_with_coverage(Own, CallSitesMap,
+        Goal0 = ProcRep0 ^ pr_defn ^ pdr_goal,
+        label_goals(LastGoalId, ContainingGoalMap, Goal0, Goal),
+        ProcRep = ProcRep0 ^ pr_defn ^ pdr_goal := Goal,
+        procrep_annotate_with_coverage(ProcRep, Own, CallSitesMap,
             SolnsCoveragePointMap, BranchCoveragePointMap,
-            ProcRep0, MaybeProcRep),
-        (
-            MaybeProcRep = ok(ProcRep),
-            MaybeReport = ok(procrep_coverage_info(PSPtr, ProcRep))
-        ;
-            MaybeProcRep = error(Error),
-            MaybeReport = error(Error)
-        )
-    ).
-
-:- func add_ps_calls_and_exits_to_map(deep, call_site_static_ptr,
-    map(reverse_goal_path, calls_and_exits)) =
-    map(reverse_goal_path, calls_and_exits).
-
-add_ps_calls_and_exits_to_map(Deep, CSSPtr, !.Map) = !:Map :-
-    lookup_call_site_statics(Deep ^ call_site_statics, CSSPtr, CSS),
-    RevGoalPath = CSS ^ css_goal_path,
-    lookup_css_own(Deep ^ css_own, CSSPtr, Own),
-    svmap.det_insert(RevGoalPath, calls_and_exits(calls(Own), exits(Own)),
-        !Map).
-
-:- pred add_pd_calls_and_exits_to_map(deep::in, call_site_static_ptr::in,
-    call_site_array_slot::in,
-    map(reverse_goal_path, calls_and_exits)::in,
-    map(reverse_goal_path, calls_and_exits)::out) is det.
-
-add_pd_calls_and_exits_to_map(Deep, CSSPtr, Slot, !Map) :-
-    (
-        Slot = slot_normal(CSDPtr),
-        csd_get_calls_and_exits(Deep, CSDPtr, Calls, Exits)
-    ;
-        Slot = slot_multi(_, CSDs),
-        foldl2(csd_get_calls_and_exits_accum(Deep), CSDs,
-            0, Calls, 0, Exits)
-    ),
-    deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
-    RevGoalPath = CSS ^ css_goal_path,
-    svmap.det_insert(RevGoalPath, calls_and_exits(Calls, Exits), !Map).
-
-:- pred csd_get_calls_and_exits(deep::in, call_site_dynamic_ptr::in,
-    int::out, int::out) is det.
-
-csd_get_calls_and_exits(Deep, CSDPtr, Calls, Exits) :-
-    ( valid_call_site_dynamic_ptr(Deep, CSDPtr) ->
-        deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
-        Own = CSD ^ csd_own_prof,
-        Calls = calls(Own),
-        Exits = exits(Own)
-    ;
-        % If the CSD is invalid then this call site was never called.
-        Calls = 0,
-        Exits = 0
-    ).
-
-:- pred csd_get_calls_and_exits_accum(deep::in, call_site_dynamic_ptr::in,
-    int::in, int::out, int::in, int::out) is det.
-
-csd_get_calls_and_exits_accum(Deep, CSDPtr, Calls0, Calls0 + NewCalls,
-        Exits0, Exits0 + NewExits) :-
-    csd_get_calls_and_exits(Deep, CSDPtr, NewCalls, NewExits).
-
-:- pred add_coverage_point_to_map(coverage_point::in,
-    map(reverse_goal_path, coverage_point)::in,
-    map(reverse_goal_path, coverage_point)::out,
-    map(reverse_goal_path, coverage_point)::in,
-    map(reverse_goal_path, coverage_point)::out) is det.
-
-add_coverage_point_to_map(CoveragePoint, !SolnsMap, !BranchMap) :-
-    CoveragePoint = coverage_point(_, GoalPath, CPType),
-    (
-        CPType = cp_type_coverage_after,
-        svmap.det_insert(GoalPath, CoveragePoint, !SolnsMap)
-    ;
-        CPType = cp_type_branch_arm,
-        svmap.det_insert(GoalPath, CoveragePoint, !BranchMap)
+            ContainingGoalMap, LastGoalId, CoverageArray),
+        MaybeReport = ok(procrep_coverage_info(PSPtr, ProcRep, CoverageArray))
     ).
 
 %-----------------------------------------------------------------------------%
Index: deep_profiler/display_report.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/display_report.m,v
retrieving revision 1.35
diff -u -p -b -r1.35 display_report.m
--- deep_profiler/display_report.m	13 Jan 2011 00:36:55 -0000	1.35
+++ deep_profiler/display_report.m	17 Jan 2011 01:31:24 -0000
@@ -2014,8 +2014,10 @@ make_proc_callers_link(Prefs, Label, PSP
     procrep_coverage_info::in, display::out) is det.
 
 display_report_procrep_coverage_info(Prefs, ProcrepCoverageReport, Display) :-
-    ProcrepCoverageReport = procrep_coverage_info(PSPtr, ProcrepCoverage),
-    print_proc_to_strings(ProcrepCoverage, ProcRepStrings),
+    ProcrepCoverageReport =
+        procrep_coverage_info(PSPtr, Procrep, CoverageArray),
+    print_proc_to_strings(get_goal_attribute_det(CoverageArray), Procrep,
+        ProcRepStrings),
     string.append_list(list(ProcRepStrings), ProcRepString),
     CoverageInfoItem = display_verbatim(ProcRepString),
 
Index: deep_profiler/mdprof_fb.automatic_parallelism.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/mdprof_fb.automatic_parallelism.m,v
retrieving revision 1.27
diff -u -p -b -r1.27 mdprof_fb.automatic_parallelism.m
--- deep_profiler/mdprof_fb.automatic_parallelism.m	13 Jan 2011 00:36:55 -0000	1.27
+++ deep_profiler/mdprof_fb.automatic_parallelism.m	17 Jan 2011 01:31:24 -0000
@@ -87,6 +87,7 @@
 :- import_module maybe.
 :- import_module require.
 :- import_module set.
+:- import_module std_util.
 :- import_module string.
 :- import_module svmap.
 
@@ -186,6 +187,8 @@ build_var_use_list(Map, Var, !List) :-
                 ipi_clique          :: clique_ptr,
                 ipi_call_sites      :: map(reverse_goal_path, cost_and_callees),
                 ipi_rec_call_sites  :: map(reverse_goal_path, cs_cost_csq),
+                ipi_coverage_array  :: goal_attr_array(coverage_info),
+                ipi_inst_map_array  :: goal_attr_array(inst_map_info),
                 ipi_recursion_type  :: recursion_type,
                 ipi_var_table       :: var_table,
                 ipi_proc_label      :: string_proc_label
@@ -603,32 +606,56 @@ candidate_parallel_conjunctions_proc(Opt
             % we can't expect to find its procedure representation.
             Candidates = map.init
         ;
-            create_dynamic_procrep_coverage_report(Deep, PDPtr,
-                MaybeCoverageReport),
+            deep_lookup_clique_index(Deep, PDPtr, CliquePtr),
+            PSPtr = PD ^ pd_proc_static,
+            deep_get_maybe_procrep(Deep, PSPtr, MaybeProcRep),
             (
-                MaybeCoverageReport = ok(CoverageReport),
-                ProcRep = CoverageReport ^ prci_proc_rep,
-                ProcRep ^ pr_defn = ProcDefnRep,
-                ProcDefnRep ^ pdr_goal = Goal0,
-                ProcDefnRep ^ pdr_var_table = VarTable,
+                MaybeProcRep = ok(ProcRep),
+                ProcDefnRep = ProcRep ^ pr_defn,
+                Goal0 = ProcDefnRep ^ pdr_goal,
+                VarTable = ProcDefnRep ^ pdr_var_table,
 
-                deep_lookup_clique_index(Deep, PDPtr, CliquePtr),
+                % Label the goals with IDs,
+                label_goals(LastGoalId, ContainingGoalMap, Goal0, Goal),
+
+                % Gather call site information.
                 proc_dynamic_paired_call_site_slots(Deep, PDPtr, Slots),
-                foldl(build_call_site_cost_and_callee_map(Deep), Slots,
+                foldl(build_dynamic_call_site_cost_and_callee_map(Deep), Slots,
                     map.init, CallSitesMap),
+
+                % Gather information about the procedure.
+                deep_lookup_pd_own(Deep, PDPtr, Own),
+
+                % Get coverage points.
+                MaybeCoveragePointsArray = PD ^ pd_maybe_coverage_points,
+                (
+                    MaybeCoveragePointsArray = yes(CoveragePointsArray),
+
+                    % Build coverage annotation.
+                    coverage_point_arrays_to_list(PS ^ ps_coverage_point_infos,
+                        CoveragePointsArray, CoveragePoints),
+                    foldl2(add_coverage_point_to_map,
+                        CoveragePoints, map.init, SolnsCoveragePointMap,
+                        map.init, BranchCoveragePointMap),
+                    goal_annotate_with_coverage(ProcLabel, Goal, Own,
+                        CallSitesMap, SolnsCoveragePointMap,
+                        BranchCoveragePointMap, ContainingGoalMap, LastGoalId,
+                        CoverageArray),
+
+                    % Build inst_map annotation.
+                    goal_annotate_with_instmap(Goal,
+                        SeenDuplicateInstantiation, _ConsumedVars, _BoundVars,
+                        initial_inst_map(ProcDefnRep), _FinalInstMap,
+                        create_goal_id_array(LastGoalId), InstMapArray),
+
                 Info = implicit_parallelism_info(Deep, ProgRep, Opts,
                     CliquePtr, CallSitesMap, RecursiveCallSiteCostMap,
-                    RecursionType, VarTable, ProcLabel),
-                some [!Goal] (
-                    !:Goal = Goal0,
-                    goal_annotate_with_instmap(!Goal,
-                        initial_inst_map(ProcDefnRep), _FinalInstMap,
-                        SeenDuplicateInstantiation, _ConsumedVars, _BoundVars),
-                    goal_to_pard_goal(Info, [], !Goal, !Messages),
+                        CoverageArray, InstMapArray, RecursionType, VarTable,
+                        ProcLabel),
+                    goal_to_pard_goal(Info, [], Goal, PardGoal, !Messages),
                     goal_get_conjunctions_worth_parallelising(Info,
-                        [], !.Goal, _, Candidates0, MessagesA),
-                    !:Messages = !.Messages ++ MessagesA
-                ),
+                        [], PardGoal, _, Candidates0, MessagesA),
+                    !:Messages = !.Messages ++ MessagesA,
                 (
                     SeenDuplicateInstantiation =
                         have_not_seen_duplicate_instantiation,
@@ -637,35 +664,29 @@ candidate_parallel_conjunctions_proc(Opt
                             VarTable),
                         Candidates0, map.init, Candidates)
                 ;
-                    SeenDuplicateInstantiation = seen_duplicate_instantiation,
+                        SeenDuplicateInstantiation =
+                            seen_duplicate_instantiation,
                     Candidates = map.init,
                     append_message(pl_proc(ProcLabel),
                         notice_duplicate_instantiation(length(Candidates0)),
                         !Messages)
                 )
             ;
-                MaybeCoverageReport = error(Error),
+                    MaybeCoveragePointsArray = no,
+                    Candidates = map.init,
+                    append_message(pl_proc(ProcLabel),
+                        error_cannot_lookup_coverage_points, !Messages)
+                )
+            ;
+                MaybeProcRep = error(_),
                 Candidates = map.init,
                 append_message(pl_proc(ProcLabel),
-                    error_coverage_procrep_error(Error), !Messages)
+                    warning_cannot_lookup_proc_defn, !Messages)
             )
         ),
         Messages = !.Messages
     ).
 
-:- type coverage_and_instmap_info
-    --->    coverage_and_instmap_info(
-                cai_coverage                :: coverage_info,
-                cai_inst_map_info           :: inst_map_info
-            ).
-
-:- instance goal_annotation_add_instmap(coverage_info,
-    coverage_and_instmap_info) where
-[
-    add_instmap(InstMap, Coverage,
-        coverage_and_instmap_info(Coverage, InstMap))
-].
-
 :- pred build_candidate_par_conjunction_maps(string_proc_label::in,
     var_table::in, candidate_par_conjunction(pard_goal_detail)::in,
     candidate_par_conjunctions::in, candidate_par_conjunctions::out) is det.
@@ -2550,7 +2571,7 @@ compute_var_use_2(Info, ArgNum, Recursio
             !Messages)
     ).
 
-:- pred goal_build_use_map(goal_rep(coverage_and_instmap_info)::in,
+:- pred goal_build_use_map(goal_rep(goal_id)::in,
     list(goal_path_step)::in, goal_cost_csq::in, implicit_parallelism_info::in,
     var_use_type::in, var_rep::in,
     map(var_rep, lazy(var_use_info))::in,
@@ -2561,15 +2582,15 @@ goal_build_use_map(Goal, RevGoalPathStep
         Cost, Info, VarUseType, Var)),
     svmap.det_insert(Var, LazyUse, !Map).
 
-:- func compute_goal_var_use_lazy(goal_rep(coverage_and_instmap_info),
-    list(goal_path_step), goal_cost_csq, implicit_parallelism_info,
-    var_use_type, var_rep) = var_use_info.
+:- func compute_goal_var_use_lazy(goal_rep(goal_id), list(goal_path_step),
+    goal_cost_csq, implicit_parallelism_info, var_use_type, var_rep)
+    = var_use_info.
 
 compute_goal_var_use_lazy(Goal, RevGoalPathSteps, Cost, Info, VarUseType, Var)
         = Use :-
     Info = implicit_parallelism_info(Deep, _ProgRep, _Params, CliquePtr,
-        CallSiteMap, RecursiveCallSiteMap, RecursionType, _VarTable,
-        _ProcLabel),
+        CallSiteMap, RecursiveCallSiteMap, CoverageArray, _InstMapArray,
+        RecursionType, _VarTable, _ProcLabel),
     CostPercall = goal_cost_get_percall(Cost),
     (
         ( RecursionType = rt_not_recursive
@@ -2581,8 +2602,8 @@ compute_goal_var_use_lazy(Goal, RevGoalP
         VarUseOptions = var_use_options(Deep, FollowCallsAcrossModules,
             VarUseType),
         var_first_use(CliquePtr, CallSiteMap, RecursiveCallSiteMap,
-            RecursionType, RecDepth, Goal, rgp(RevGoalPathSteps),
-            CostPercall, Var, VarUseOptions, Use)
+            CoverageArray, RecursionType, RecDepth, Goal,
+            rgp(RevGoalPathSteps), CostPercall, Var, VarUseOptions, Use)
     ;
         ( RecursionType = rt_divide_and_conquer(_, _)
         ; RecursionType = rt_mutual_recursion(_)
@@ -2601,10 +2622,6 @@ compute_goal_var_use_lazy(Goal, RevGoalP
         )
     ).
 
-:- instance goal_annotation_with_coverage(coverage_and_instmap_info) where [
-    (get_coverage(Goal) = Goal ^ goal_annotation ^ cai_coverage)
-].
-
 :- pred implicit_par_info_intermodule_var_use(implicit_parallelism_info::in,
     intermodule_var_use::out) is det.
 
@@ -2689,13 +2706,13 @@ var_get_mode(InstMapBefore, InstMapAfter
     % Transform a goal in a conjunction into a pard_goal.
     %
 :- pred goal_to_pard_goal(implicit_parallelism_info::in,
-    list(goal_path_step)::in, goal_rep(coverage_and_instmap_info)::in,
+    list(goal_path_step)::in, goal_rep(goal_id)::in,
     pard_goal_detail::out, cord(message)::in, cord(message)::out) is det.
 
 goal_to_pard_goal(Info, RevGoalPathSteps, !Goal, !Messages) :-
-    !.Goal = goal_rep(GoalExpr0, Detism, CoverageAndInstMapInfo),
-    InstMapInfo = CoverageAndInstMapInfo ^ cai_inst_map_info,
-    Coverage = CoverageAndInstMapInfo ^ cai_coverage,
+    !.Goal = goal_rep(GoalExpr0, Detism, GoalId),
+    InstMapInfo = get_goal_attribute_det(Info ^ ipi_inst_map_array, GoalId),
+    Coverage = get_goal_attribute_det(Info ^ ipi_coverage_array, GoalId),
     get_coverage_before_det(Coverage, Before),
     (
         (
@@ -2787,7 +2804,7 @@ goal_to_pard_goal(Info, RevGoalPathSteps
     !:Goal = goal_rep(GoalExpr, Detism, PardGoalAnnotation).
 
 :- pred conj_to_pard_goals(implicit_parallelism_info::in,
-    list(goal_path_step)::in, goal_rep(coverage_and_instmap_info)::in,
+    list(goal_path_step)::in, goal_rep(goal_id)::in,
     pard_goal_detail::out, int::in, int::out,
     cord(message)::in, cord(message)::out) is det.
 
@@ -2797,7 +2814,7 @@ conj_to_pard_goals(Info, RevGoalPathStep
     !:ConjNum = !.ConjNum + 1.
 
 :- pred disj_to_pard_goals(implicit_parallelism_info::in,
-    list(goal_path_step)::in, goal_rep(coverage_and_instmap_info)::in,
+    list(goal_path_step)::in, goal_rep(goal_id)::in,
     pard_goal_detail::out, int::in, int::out,
     cord(message)::in, cord(message)::out) is det.
 
@@ -2807,7 +2824,7 @@ disj_to_pard_goals(Info, RevGoalPathStep
     !:DisjNum = !.DisjNum + 1.
 
 :- pred case_to_pard_goal(implicit_parallelism_info::in,
-    list(goal_path_step)::in, case_rep(coverage_and_instmap_info)::in,
+    list(goal_path_step)::in, case_rep(goal_id)::in,
     case_rep(pard_goal_detail_annotation)::out, int::in, int::out,
     cord(message)::in, cord(message)::out) is det.
 
@@ -2915,10 +2932,6 @@ simple_goal_cost(Calls) = Cost :-
                 im_bound_vars       :: set(var_rep)
             ).
 
-:- typeclass goal_annotation_add_instmap(A, B) where [
-    pred add_instmap(inst_map_info::in, A::in, B::out) is det
-].
-
     % Note: It may be useful to add other annotations such as goal path or cost
     % information.
     %
@@ -2928,53 +2941,50 @@ simple_goal_cost(Calls) = Cost :-
     % Vars is the set of variables used by this goal, both consumed and
     % produced.
     %
-:- pred goal_annotate_with_instmap(goal_rep(A)::in, goal_rep(B)::out,
-    inst_map::in, inst_map::out, seen_duplicate_instantiation::out,
-    set(var_rep)::out, set(var_rep)::out) is det
-    <= goal_annotation_add_instmap(A, B).
-
-goal_annotate_with_instmap(Goal0, Goal, !InstMap, SeenDuplicateInstantiation,
-        ConsumedVars, BoundVars) :-
-    Goal0 = goal_rep(GoalExpr0, Detism, Ann0),
+:- pred goal_annotate_with_instmap(goal_rep(goal_id)::in,
+    seen_duplicate_instantiation::out,
+    set(var_rep)::out, set(var_rep)::out,
+    inst_map::in, inst_map::out,
+    goal_attr_array(inst_map_info)::gaa_di,
+    goal_attr_array(inst_map_info)::gaa_uo) is det.
+
+goal_annotate_with_instmap(Goal, SeenDuplicateInstantiation, ConsumedVars,
+        BoundVars, !InstMap, !InstMapArray) :-
+    Goal = goal_rep(GoalExpr, _, GoalId),
     InstMapBefore = !.InstMap,
     (
-        GoalExpr0 = conj_rep(Conjs0),
-        conj_annotate_with_instmap(Conjs0, Conjs, !InstMap,
-            SeenDuplicateInstantiation, ConsumedVars, BoundVars),
-        GoalExpr = conj_rep(Conjs)
-    ;
-        GoalExpr0 = disj_rep(Disjs0),
-        disj_annotate_with_instmap(Disjs0, Disjs, !InstMap,
-            SeenDuplicateInstantiation, ConsumedVars, BoundVars),
-        GoalExpr = disj_rep(Disjs)
+        GoalExpr = conj_rep(Conjs),
+        conj_annotate_with_instmap(Conjs, SeenDuplicateInstantiation,
+            ConsumedVars, BoundVars, !InstMap, !InstMapArray)
     ;
-        GoalExpr0 = switch_rep(Var, CanFail, Cases0),
-        switch_annotate_with_instmap(Cases0, Cases, !InstMap,
-            SeenDuplicateInstantiation, ConsumedVars0, BoundVars),
-        set.insert(ConsumedVars0, Var, ConsumedVars),
-        GoalExpr = switch_rep(Var, CanFail, Cases)
+        GoalExpr = disj_rep(Disjs),
+        disj_annotate_with_instmap(Disjs, SeenDuplicateInstantiation,
+            ConsumedVars, BoundVars, !InstMap, !InstMapArray)
     ;
-        GoalExpr0 = ite_rep(Cond0, Then0, Else0),
-        ite_annotate_with_instmap(Cond0, Cond, Then0, Then, Else0, Else,
-            !InstMap, SeenDuplicateInstantiation, ConsumedVars, BoundVars),
-        GoalExpr = ite_rep(Cond, Then, Else)
+        GoalExpr = switch_rep(Var, _CanFail, Cases),
+        switch_annotate_with_instmap(Cases, SeenDuplicateInstantiation,
+            ConsumedVars0, BoundVars, !InstMap, !InstMapArray),
+        set.insert(ConsumedVars0, Var, ConsumedVars)
+    ;
+        GoalExpr = ite_rep(Cond, Then, Else),
+        ite_annotate_with_instmap(Cond, Then, Else,
+            SeenDuplicateInstantiation, ConsumedVars, BoundVars,
+            !InstMap, !InstMapArray)
     ;
         % XXX: Not all scope goals can produce variables, in fact some are used
         % to isolate variables that aren't named apart.  But other scope goals
         % can bind variables.  We don't know which we're looking at here.
-        GoalExpr0 = scope_rep(Subgoal0, MaybeCut),
-        goal_annotate_with_instmap(Subgoal0, Subgoal, !InstMap,
-            SeenDuplicateInstantiation, ConsumedVars, BoundVars),
-        GoalExpr = scope_rep(Subgoal, MaybeCut)
+        GoalExpr = scope_rep(Subgoal, _MaybeCut),
+        goal_annotate_with_instmap(Subgoal, SeenDuplicateInstantiation,
+            ConsumedVars, BoundVars, !InstMap, !InstMapArray)
     ;
-        GoalExpr0 = negation_rep(Subgoal0),
+        GoalExpr = negation_rep(Subgoal),
         % A negated goal cannot affect instantiation.
-        goal_annotate_with_instmap(Subgoal0, Subgoal, !.InstMap,
-            _InstMap, SeenDuplicateInstantiation, ConsumedVars, _),
-        BoundVars = set.init,
-        GoalExpr = negation_rep(Subgoal)
+        goal_annotate_with_instmap(Subgoal, SeenDuplicateInstantiation,
+            ConsumedVars, _, !.InstMap, _InstMap, !InstMapArray),
+        BoundVars = set.init
     ;
-        GoalExpr0 = atomic_goal_rep(File, Line, BoundVarsList, AtomicGoal),
+        GoalExpr = atomic_goal_rep(_File, _Line, BoundVarsList, AtomicGoal),
         % The binding of a variable may depend on any number of other
         % variables, and recursively the variables that those depended-on
         % variables depend upon.
@@ -2987,48 +2997,50 @@ goal_annotate_with_instmap(Goal0, Goal, 
         BoundVars = set.from_list(BoundVarsList),
         set.difference(Vars, BoundVars, ConsumedVars),
         inst_map_ground_vars(BoundVarsList, ConsumedVars, !InstMap,
-            SeenDuplicateInstantiation),
-        GoalExpr = atomic_goal_rep(File, Line, BoundVarsList, AtomicGoal)
+            SeenDuplicateInstantiation)
     ),
     InstMapAfter = !.InstMap,
     InstMapInfo = inst_map_info(InstMapBefore, InstMapAfter, ConsumedVars,
         BoundVars),
-    add_instmap(InstMapInfo, Ann0, Ann),
-    Goal = goal_rep(GoalExpr, Detism, Ann).
+    update_goal_attribute(GoalId, InstMapInfo, !InstMapArray).
 
-:- pred conj_annotate_with_instmap(list(goal_rep(A))::in,
-    list(goal_rep(B))::out, inst_map::in, inst_map::out,
-    seen_duplicate_instantiation::out, set(var_rep)::out, set(var_rep)::out)
-    is det <= goal_annotation_add_instmap(A, B).
-
-conj_annotate_with_instmap([], [], !InstMap,
-    have_not_seen_duplicate_instantiation, set.init, set.init).
-conj_annotate_with_instmap([Conj0 | Conjs0], [Conj | Conjs], !InstMap,
-        SeenDuplicateInstantiation, ConsumedVars, BoundVars) :-
-    goal_annotate_with_instmap(Conj0, Conj, !InstMap,
-        SeenDuplicateInstantiationHead, ConsumedVarsHead, BoundVarsHead),
-    conj_annotate_with_instmap(Conjs0, Conjs, !InstMap,
-        SeenDuplicateInstantiationTail, ConsumedVarsTail, BoundVarsTail),
+:- pred conj_annotate_with_instmap(list(goal_rep(goal_id))::in,
+    seen_duplicate_instantiation::out, set(var_rep)::out, set(var_rep)::out,
+    inst_map::in, inst_map::out,
+    goal_attr_array(inst_map_info)::gaa_di,
+    goal_attr_array(inst_map_info)::gaa_uo) is det.
+
+conj_annotate_with_instmap([], have_not_seen_duplicate_instantiation,
+        set.init, set.init, !InstMap, !InstMapArray).
+conj_annotate_with_instmap([Conj | Conjs], SeenDuplicateInstantiation,
+        ConsumedVars, BoundVars, !InstMap, !InstMapArray) :-
+    goal_annotate_with_instmap(Conj, SeenDuplicateInstantiationHead,
+        ConsumedVarsHead, BoundVarsHead, !InstMap, !InstMapArray),
+    conj_annotate_with_instmap(Conjs, SeenDuplicateInstantiationTail,
+        ConsumedVarsTail, BoundVarsTail, !InstMap, !InstMapArray),
     set.union(ConsumedVarsTail, ConsumedVarsHead, ConsumedVars),
     set.union(BoundVarsTail, BoundVarsHead, BoundVars),
     SeenDuplicateInstantiation = merge_seen_duplicate_instantiation(
         SeenDuplicateInstantiationHead,
         SeenDuplicateInstantiationTail).
 
-:- pred disj_annotate_with_instmap(list(goal_rep(A))::in,
-    list(goal_rep(B))::out, inst_map::in, inst_map::out,
-    seen_duplicate_instantiation::out, set(var_rep)::out, set(var_rep)::out)
-    is det <= goal_annotation_add_instmap(A, B).
-
-disj_annotate_with_instmap([], [], !InstMap,
-        have_not_seen_duplicate_instantiation, set.init, set.init).
-disj_annotate_with_instmap([Disj0 | Disjs0], [Disj | Disjs], InstMap0, InstMap,
-        SeenDuplicateInstantiation, ConsumedVars, BoundVars) :-
-    HeadDetism = Disj0 ^ goal_detism_rep,
-    goal_annotate_with_instmap(Disj0, Disj, InstMap0, InstMapHead,
-        SeenDuplicateInstantiationHead, ConsumedVarsHead, BoundVarsHead),
-    disj_annotate_with_instmap(Disjs0, Disjs, InstMap0, InstMapTail,
-        SeenDuplicateInstantiationTail, ConsumedVarsTail, BoundVarsTail),
+:- pred disj_annotate_with_instmap(list(goal_rep(goal_id))::in,
+    seen_duplicate_instantiation::out, set(var_rep)::out, set(var_rep)::out,
+    inst_map::in, inst_map::out,
+    goal_attr_array(inst_map_info)::gaa_di,
+    goal_attr_array(inst_map_info)::gaa_uo) is det.
+
+disj_annotate_with_instmap([], have_not_seen_duplicate_instantiation,
+        set.init, set.init, !InstMap, !InstMapArray).
+disj_annotate_with_instmap([Disj | Disjs], SeenDuplicateInstantiation,
+        ConsumedVars, BoundVars, InstMap0, InstMap, !InstMapArray) :-
+    HeadDetism = Disj ^ goal_detism_rep,
+    goal_annotate_with_instmap(Disj, SeenDuplicateInstantiationHead,
+        ConsumedVarsHead, BoundVarsHead, InstMap0, InstMapHead,
+        !InstMapArray),
+    disj_annotate_with_instmap(Disjs, SeenDuplicateInstantiationTail,
+        ConsumedVarsTail, BoundVarsTail, InstMap0, InstMapTail,
+        !InstMapArray),
 
     set.union(ConsumedVarsTail, ConsumedVarsHead, ConsumedVars),
 
@@ -3052,23 +3064,24 @@ disj_annotate_with_instmap([Disj0 | Disj
         SeenDuplicateInstantiationHead,
         SeenDuplicateInstantiationTail).
 
-:- pred switch_annotate_with_instmap(list(case_rep(A))::in,
-    list(case_rep(B))::out, inst_map::in, inst_map::out,
-    seen_duplicate_instantiation::out, set(var_rep)::out, set(var_rep)::out)
-    is det <= goal_annotation_add_instmap(A, B).
-
-switch_annotate_with_instmap([], [], !InstMap,
-        have_not_seen_duplicate_instantiation, set.init, set.init).
-switch_annotate_with_instmap([Case0 | Cases0], [Case | Cases],
-        InstMap0, InstMap, SeenDuplicateInstantiation,
-        ConsumedVars, BoundVars) :-
-    Case0 = case_rep(ConsIdArity, ExtraConsIdAritys, Goal0),
-    HeadDetism = Goal0 ^ goal_detism_rep,
-    goal_annotate_with_instmap(Goal0, Goal, InstMap0, InstMapHead,
-        SeenDuplicateInstantiationHead, ConsumedVarsHead, BoundVarsHead),
-    Case = case_rep(ConsIdArity, ExtraConsIdAritys, Goal),
-    switch_annotate_with_instmap(Cases0, Cases, InstMap0, InstMapTail,
-        SeenDuplicateInstantiationTail, ConsumedVarsTail, BoundVarsTail),
+:- pred switch_annotate_with_instmap(list(case_rep(goal_id))::in,
+    seen_duplicate_instantiation::out, set(var_rep)::out, set(var_rep)::out,
+    inst_map::in, inst_map::out,
+    goal_attr_array(inst_map_info)::gaa_di,
+    goal_attr_array(inst_map_info)::gaa_uo) is det.
+
+switch_annotate_with_instmap([], have_not_seen_duplicate_instantiation,
+        set.init, set.init, !InstMap, !InstMapArray).
+switch_annotate_with_instmap([Case | Cases], SeenDuplicateInstantiation,
+        ConsumedVars, BoundVars, InstMap0, InstMap, !InstMapArray) :-
+    Case = case_rep(_, _, Goal),
+    HeadDetism = Goal ^ goal_detism_rep,
+    goal_annotate_with_instmap(Goal, SeenDuplicateInstantiationHead,
+        ConsumedVarsHead, BoundVarsHead, InstMap0, InstMapHead,
+        !InstMapArray),
+    switch_annotate_with_instmap(Cases, SeenDuplicateInstantiationTail,
+        ConsumedVarsTail, BoundVarsTail, InstMap0, InstMapTail,
+        !InstMapArray),
     set.union(ConsumedVarsTail, ConsumedVarsHead, ConsumedVars),
     % merge_inst_map requires the detism of goals that produce both inst maps,
     % we can create fake values that satisfy merge_inst_map easily.
@@ -3086,22 +3099,24 @@ switch_annotate_with_instmap([Case0 | Ca
         SeenDuplicateInstantiationHead,
         SeenDuplicateInstantiationTail).
 
-:- pred ite_annotate_with_instmap(goal_rep(A)::in, goal_rep(B)::out,
-    goal_rep(A)::in, goal_rep(B)::out,
-    goal_rep(A)::in, goal_rep(B)::out,
+:- pred ite_annotate_with_instmap(goal_rep(goal_id)::in,
+    goal_rep(goal_id)::in, goal_rep(goal_id)::in,
+    seen_duplicate_instantiation::out, set(var_rep)::out, set(var_rep)::out,
     inst_map::in, inst_map::out,
-    seen_duplicate_instantiation::out, set(var_rep)::out, set(var_rep)::out)
-    is det <= goal_annotation_add_instmap(A, B).
+    goal_attr_array(inst_map_info)::gaa_di,
+    goal_attr_array(inst_map_info)::gaa_uo) is det.
 
-ite_annotate_with_instmap(Cond0, Cond, Then0, Then, Else0, Else,
-        InstMap0, InstMap, SeenDuplicateInstantiation,
-        ConsumedVars, BoundVars) :-
-    goal_annotate_with_instmap(Cond0, Cond, InstMap0, InstMapAfterCond,
-        SeenDuplicateInstantiationCond, ConsumedVarsCond, _BoundVarsCond),
-    goal_annotate_with_instmap(Then0, Then, InstMapAfterCond, InstMapAfterThen,
-        SeenDuplicateInstantiationThen, ConsumedVarsThen, BoundVarsThen),
-    goal_annotate_with_instmap(Else0, Else, InstMap0, InstMapAfterElse,
-        SeenDuplicateInstantiationElse, ConsumedVarsElse, BoundVarsElse),
+ite_annotate_with_instmap(Cond, Then, Else, SeenDuplicateInstantiation,
+        ConsumedVars, BoundVars, InstMap0, InstMap, !InstMapArray) :-
+    goal_annotate_with_instmap(Cond, SeenDuplicateInstantiationCond,
+        ConsumedVarsCond, _BoundVarsCond, InstMap0, InstMapAfterCond,
+        !InstMapArray),
+    goal_annotate_with_instmap(Then, SeenDuplicateInstantiationThen,
+        ConsumedVarsThen, BoundVarsThen, InstMapAfterCond, InstMapAfterThen,
+        !InstMapArray),
+    goal_annotate_with_instmap(Else, SeenDuplicateInstantiationElse,
+        ConsumedVarsElse, BoundVarsElse, InstMap0, InstMapAfterElse,
+        !InstMapArray),
     (
         SeenDuplicateInstantiationCond = have_not_seen_duplicate_instantiation,
         SeenDuplicateInstantiationThen = have_not_seen_duplicate_instantiation,
@@ -3367,8 +3382,8 @@ format_parallel_conjuncts(VarTable, Inde
         (
             GoalsTail = [],
             % A singleton conjunction gets printed as a single goal.
-            print_goal_to_strings(VarTable, Indent + 1, RevInnerGoalPathSteps,
-                Goal, ConjReport)
+            print_goal_to_strings(print_goal_info(id, VarTable), Indent + 1,
+                RevInnerGoalPathSteps, Goal, ConjReport)
         ;
             GoalsTail = [_ | _],
             Cost = foldl(
@@ -3419,7 +3434,7 @@ format_sequential_conjunction(VarTable, 
 format_sequential_conjuncts(_, _, _, [], !ConjNum, !Report).
 format_sequential_conjuncts(VarTable, Indent, RevGoalPathSteps, [Conj | Conjs],
         !ConjNum, !Report) :-
-    print_goal_to_strings(VarTable, Indent,
+    print_goal_to_strings(print_goal_info(id, VarTable), Indent,
         [step_conj(!.ConjNum) | RevGoalPathSteps], Conj, ConjReport),
     !:Report = !.Report ++ ConjReport,
     !:ConjNum = !.ConjNum + 1,
Index: deep_profiler/message.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/message.m,v
retrieving revision 1.13
diff -u -p -b -r1.13 message.m
--- deep_profiler/message.m	13 Jan 2011 00:36:55 -0000	1.13
+++ deep_profiler/message.m	17 Jan 2011 01:31:24 -0000
@@ -147,7 +147,7 @@
             % We don't yet handle clique_proc_reports with multiple proc
             % dynamics.
 
-    ;       error_coverage_procrep_error(string)
+    ;       error_cannot_lookup_coverage_points
             % An error in the generation of a coverage_procrep report.
 
     ;       error_exception_thrown(string).
@@ -293,8 +293,8 @@ message_type_to_level(MsgType) = MsgLeve
         MsgLevel = message_warning
     ;
         ( MsgType = error_extra_proc_dynamics_in_clique_proc
-        ; MsgType = error_coverage_procrep_error(_)
         ; MsgType = error_exception_thrown(_)
+        ; MsgType = error_cannot_lookup_coverage_points
         ),
         MsgLevel = message_error
     ).
@@ -308,6 +308,9 @@ message_type_to_string(MessageType) = Co
         MessageType = info_found_candidate_conjunction,
         String = "Found candidate conjunction"
     ;
+        MessageType = error_cannot_lookup_coverage_points,
+        String = "Cannot lookup coverage points"
+    ;
         (
             MessageType = info_found_conjs_above_callsite_threshold(Num),
             MessageStr = "Found %d conjuncts above callsite threashold"
@@ -355,9 +358,6 @@ message_type_to_string(MessageType) = Co
             ++ " handled."
     ;
         (
-            MessageType = error_coverage_procrep_error(ErrorStr),
-            Template = "Error generating coverage procedure report: %s"
-        ;
             MessageType = error_exception_thrown(ErrorStr),
             Template = "Exception thrown: %s"
         ;
Index: deep_profiler/program_representation_utils.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/program_representation_utils.m,v
retrieving revision 1.30
diff -u -p -b -r1.30 program_representation_utils.m
--- deep_profiler/program_representation_utils.m	13 Jan 2011 00:36:55 -0000	1.30
+++ deep_profiler/program_representation_utils.m	17 Jan 2011 01:31:24 -0000
@@ -38,6 +38,13 @@
     %
 :- pred print_module_to_strings(module_rep::in, cord(string)::out) is det.
 
+    % Print a procedure to a string representation using a higher order value
+    % to lookup goal attributes.
+    %
+:- pred print_proc_to_strings(func(goal_id) = GoalAnn, proc_rep(goal_id),
+    cord(string)) <= goal_annotation(GoalAnn).
+:- mode print_proc_to_strings(func(in) = out is det, in, out) is det.
+
     % Print a procedure to a string representation.
     %
 :- pred print_proc_to_strings(proc_rep(GoalAnn)::in, cord(string)::out) is det
@@ -47,12 +54,19 @@
     %
 :- pred print_proc_label_to_string(string_proc_label::in, string::out) is det.
 
-    % print_goal_to_strings(VarTable, Indent, RevGoalPathSteps, Goal, Strings):
+:- type print_goal_info(Key, GoalAnn)
+    --->    print_goal_info(
+                pgi_lookup_annotation       :: (func(Key) = GoalAnn),
+                pgi_var_table               :: var_table
+            ).
+
+    % print_goal_to_strings(Lookup, VarTable, Indent, RevGoalPathSteps, Goal,
+    %   Strings):
     %
     % Print a goal (recursively) to a string representation.
     %
-:- pred print_goal_to_strings(var_table::in, int::in, list(goal_path_step)::in,
-    goal_rep(GoalAnn)::in, cord(string)::out) is det
+:- pred print_goal_to_strings(print_goal_info(T, GoalAnn)::in, int::in,
+    list(goal_path_step)::in, goal_rep(T)::in, cord(string)::out) is det
     <= goal_annotation(GoalAnn).
 
 %----------------------------------------------------------------------------%
@@ -72,6 +86,15 @@
 
 %----------------------------------------------------------------------------%
 
+    % Goal IDs are a more efficient way to identify goals than goal paths.
+    %
+    % The allow annotations to be kept in an array indexed by the goal id.
+    %
+:- pred label_goals(goal_id::out, containing_goal_map::out,
+    goal_rep(T)::in, goal_rep(goal_id)::out) is det.
+
+%----------------------------------------------------------------------------%
+
     % Search a program representation for the given procedure and return its
     % procedure representation if found, otherwise fail.
     %
@@ -183,11 +206,13 @@
 
 :- import_module array.
 :- import_module bool.
+:- import_module counter.
 :- import_module int.
 :- import_module io.
 :- import_module map.
 :- import_module maybe.
 :- import_module require.
+:- import_module std_util.
 :- import_module svmap.
 
 %----------------------------------------------------------------------------%
@@ -209,7 +234,17 @@ accumulate_print_proc_to_strings(_, Proc
     print_proc_to_strings(Proc, ProcStrings),
     !:Strings = !.Strings ++ ProcStrings.
 
+print_proc_to_strings(Lookup, ProcRep, Strings) :-
+    print_proc_to_strings_2(Lookup, ProcRep, Strings).
+
 print_proc_to_strings(ProcRep, Strings) :-
+    print_proc_to_strings_2(id, ProcRep, Strings).
+
+:- pred print_proc_to_strings_2(func(X) = GoalAnn, proc_rep(X),
+    cord(string)) <= goal_annotation(GoalAnn).
+:- mode print_proc_to_strings_2(func(in) = out is det, in, out) is det.
+
+print_proc_to_strings_2(Lookup, ProcRep, Strings) :-
     ProcRep = proc_rep(ProcLabel, ProcDefnRep),
     ProcDefnRep = proc_defn_rep(ArgVarReps, GoalRep, VarTable, Detism),
     print_proc_label_to_string(ProcLabel, ProcLabelString0),
@@ -217,7 +252,8 @@ print_proc_to_strings(ProcRep, Strings) 
     ProcLabelString = DetismString ++ cord.singleton(" ") ++
         cord.singleton(ProcLabelString0),
     print_args_to_strings(print_head_var, VarTable, ArgVarReps, ArgsString),
-    print_goal_to_strings(VarTable, 1, [], GoalRep, GoalString),
+    print_goal_to_strings(print_goal_info(Lookup, VarTable), 1, [], GoalRep,
+        GoalString),
     Strings = ProcLabelString ++ ArgsString ++ cord.singleton(" :-\n") ++
         GoalString ++ nl.
 
@@ -243,16 +279,17 @@ print_proc_label_to_string(ProcLabel, St
 
 %-----------------------------------------------------------------------------%
 
-print_goal_to_strings(VarTable, Indent, RevGoalPathSteps, GoalRep, Strings) :-
-    GoalRep = goal_rep(GoalExprRep, DetismRep, GoalAnnotation),
+print_goal_to_strings(Info, Indent, RevGoalPathSteps, GoalRep, Strings) :-
+    GoalRep = goal_rep(GoalExprRep, DetismRep, AnnotationKey),
+    VarTable = Info ^ pgi_var_table,
     (
         GoalExprRep = conj_rep(ConjGoalReps),
-        print_conj_to_strings(VarTable, Indent, RevGoalPathSteps,
+        print_conj_to_strings(Info, Indent, RevGoalPathSteps,
             ConjGoalReps, ExprString)
     ;
         GoalExprRep = disj_rep(DisjGoalReps),
-        print_disj_to_strings(VarTable, Indent, RevGoalPathSteps, 1,
-            DisjGoalReps, no, DisjString),
+        print_disj_to_strings(Info, Indent, RevGoalPathSteps, 1, DisjGoalReps,
+            no, DisjString),
         ExprString = indent(Indent) ++
             cord.singleton("(\n") ++ DisjString ++ indent(Indent) ++
             cord.singleton(")\n")
@@ -261,7 +298,7 @@ print_goal_to_strings(VarTable, Indent, 
         lookup_var_name(VarTable, SwitchVarRep, SwitchVarName),
         string.format("%s switch on %s\n",
             [s(string(CanFail)), s(SwitchVarName)], SwitchOnString),
-        print_switch_to_strings(VarTable, Indent, RevGoalPathSteps, 1,
+        print_switch_to_strings(Info, Indent + 1, RevGoalPathSteps, 1,
             CasesRep, no, SwitchString),
         ExprString = indent(Indent) ++ cord.singleton(SwitchOnString) ++
             indent(Indent) ++ cord.singleton("(\n") ++ SwitchString ++
@@ -271,11 +308,11 @@ print_goal_to_strings(VarTable, Indent, 
         RevGoalPathStepsCond = [step_ite_cond | RevGoalPathSteps],
         RevGoalPathStepsThen = [step_ite_then | RevGoalPathSteps],
         RevGoalPathStepsElse = [step_ite_else | RevGoalPathSteps],
-        print_goal_to_strings(VarTable, Indent + 1, RevGoalPathStepsCond,
+        print_goal_to_strings(Info, Indent + 1, RevGoalPathStepsCond,
             CondRep, CondString),
-        print_goal_to_strings(VarTable, Indent + 1, RevGoalPathStepsThen,
+        print_goal_to_strings(Info, Indent + 1, RevGoalPathStepsThen,
             ThenRep, ThenString),
-        print_goal_to_strings(VarTable, Indent + 1, RevGoalPathStepsElse,
+        print_goal_to_strings(Info, Indent + 1, RevGoalPathStepsElse,
             ElseRep, ElseString),
         IndentString = indent(Indent),
         ExprString = IndentString ++ cord.singleton("(\n") ++ CondString ++
@@ -285,7 +322,7 @@ print_goal_to_strings(VarTable, Indent, 
     ;
         GoalExprRep = negation_rep(SubGoalRep),
         RevSubGoalPathSteps = [step_neg | RevGoalPathSteps],
-        print_goal_to_strings(VarTable, Indent + 1, RevSubGoalPathSteps,
+        print_goal_to_strings(Info, Indent + 1, RevSubGoalPathSteps,
             SubGoalRep, SubGoalString),
         ExprString = indent(Indent) ++ cord.singleton("not (\n") ++
             SubGoalString ++ indent(Indent) ++ cord.singleton(")\n")
@@ -299,7 +336,7 @@ print_goal_to_strings(VarTable, Indent, 
             CutString = cord.empty
         ),
         RevSubGoalPathSteps = [step_scope(MaybeCut) | RevGoalPathSteps],
-        print_goal_to_strings(VarTable, Indent + 1, RevSubGoalPathSteps,
+        print_goal_to_strings(Info, Indent + 1, RevSubGoalPathSteps,
             SubGoalRep, SubGoalString),
         ExprString = indent(Indent) ++ cord.singleton("scope") ++ CutString ++
             cord.singleton(" (\n") ++
@@ -320,6 +357,8 @@ print_goal_to_strings(VarTable, Indent, 
     ),
     detism_to_string(DetismRep, DetismString),
     DetismLine = LinePrefix ++ DetismString ++ nl,
+    LookupAnnotation = Info ^ pgi_lookup_annotation,
+    GoalAnnotation = LookupAnnotation(AnnotationKey),
     print_goal_annotation_to_strings(VarTable, GoalAnnotation,
         GoalAnnotationLines0),
     ( is_empty(GoalAnnotationLines0) ->
@@ -344,28 +383,28 @@ print_goal_to_strings(VarTable, Indent, 
         ++ ExtraLineForConjunctions
         ++ ExprString.
 
-:- pred print_conj_to_strings(var_table::in, int::in,
-    list(goal_path_step)::in, list(goal_rep(GoalAnn))::in,
+:- pred print_conj_to_strings(print_goal_info(T, GoalAnn)::in, int::in,
+    list(goal_path_step)::in, list(goal_rep(T))::in,
     cord(string)::out) is det
     <= goal_annotation(GoalAnn).
 
-print_conj_to_strings(VarTable, Indent, RevGoalPathSteps, GoalReps, Strings) :-
+print_conj_to_strings(Info, Indent, RevGoalPathSteps, GoalReps, Strings) :-
     (
         GoalReps = [],
         Strings = cord.snoc(indent(Indent), "true\n")
     ;
         GoalReps = [_ | _],
-        print_conj_to_strings_2(VarTable, Indent, RevGoalPathSteps, 1,
-            GoalReps, Strings)
+        print_conj_to_strings_2(Info, Indent, RevGoalPathSteps, 1, GoalReps,
+            Strings)
     ).
 
-:- pred print_conj_to_strings_2(var_table::in, int::in,
-    list(goal_path_step)::in, int::in, list(goal_rep(GoalAnn))::in,
+:- pred print_conj_to_strings_2(print_goal_info(T, GoalAnn)::in, int::in,
+    list(goal_path_step)::in, int::in, list(goal_rep(T))::in,
     cord(string)::out)
     is det <= goal_annotation(GoalAnn).
 
 print_conj_to_strings_2(_, _Indent, _, _, [], cord.empty).
-print_conj_to_strings_2(VarTable, Indent, RevGoalPathSteps, ConjNum,
+print_conj_to_strings_2(Info, Indent, RevGoalPathSteps, ConjNum,
         [GoalRep | GoalReps], Strings) :-
     % We use the absence of a separator to denote conjunction.
     %
@@ -373,9 +412,9 @@ print_conj_to_strings_2(VarTable, Indent
     % not last in a conjunction, but that would be significant work,
     % and (at least for now) there is no real need for it.
     RevSubGoalPathSteps = [step_conj(ConjNum) | RevGoalPathSteps],
-    print_goal_to_strings(VarTable, Indent, RevSubGoalPathSteps,
-        GoalRep, HeadGoalString),
-    print_conj_to_strings_2(VarTable, Indent, RevGoalPathSteps, ConjNum + 1,
+    print_goal_to_strings(Info, Indent, RevSubGoalPathSteps, GoalRep,
+        HeadGoalString),
+    print_conj_to_strings_2(Info, Indent, RevGoalPathSteps, ConjNum + 1,
         GoalReps, TailGoalsString),
     (
         GoalReps = [],
@@ -386,13 +425,13 @@ print_conj_to_strings_2(VarTable, Indent
     ),
     Strings = HeadGoalString ++ Separator ++ TailGoalsString.
 
-:- pred print_disj_to_strings(var_table::in, int::in,
-    list(goal_path_step)::in, int::in, list(goal_rep(GoalAnn))::in, bool::in,
+:- pred print_disj_to_strings(print_goal_info(T, GoalAnn)::in, int::in,
+    list(goal_path_step)::in, int::in, list(goal_rep(T))::in, bool::in,
     cord(string)::out)
     is det <= goal_annotation(GoalAnn).
 
 print_disj_to_strings(_, _Indent, _, _, [], _PrintSemi, cord.empty).
-print_disj_to_strings(VarTable, Indent, RevGoalPathSteps, DisjNum,
+print_disj_to_strings(Info, Indent, RevGoalPathSteps, DisjNum,
         [GoalRep | GoalReps], PrintSemi, Strings) :-
     (
         PrintSemi = no,
@@ -402,19 +441,19 @@ print_disj_to_strings(VarTable, Indent, 
         DelimString = indent(Indent) ++ cord.singleton(";\n")
     ),
     RevSubGoalPathSteps = [step_disj(DisjNum) | RevGoalPathSteps],
-    print_goal_to_strings(VarTable, Indent + 1, RevSubGoalPathSteps,
-        GoalRep, HeadGoalString),
-    print_disj_to_strings(VarTable, Indent, RevGoalPathSteps, DisjNum + 1,
+    print_goal_to_strings(Info, Indent + 1, RevSubGoalPathSteps, GoalRep,
+        HeadGoalString),
+    print_disj_to_strings(Info, Indent, RevGoalPathSteps, DisjNum + 1,
         GoalReps, yes, TailGoalsString),
     Strings = DelimString ++ HeadGoalString ++ TailGoalsString.
 
-:- pred print_switch_to_strings(var_table::in, int::in,
-    list(goal_path_step)::in, int::in, list(case_rep(GoalAnn))::in, bool::in,
+:- pred print_switch_to_strings(print_goal_info(T, GoalAnn)::in, int::in,
+    list(goal_path_step)::in, int::in, list(case_rep(T))::in, bool::in,
     cord(string)::out) is det
     <= goal_annotation(GoalAnn).
 
 print_switch_to_strings(_, _Indent, _, _, [], _PrintSemi, cord.empty).
-print_switch_to_strings(VarTable, Indent, RevGoalPathSteps, CaseNum,
+print_switch_to_strings(Info, Indent, RevGoalPathSteps, CaseNum,
         [CaseRep | CaseReps], PrintSemi, Strings) :-
     (
         PrintSemi = no,
@@ -429,9 +468,9 @@ print_switch_to_strings(VarTable, Indent
     list.map(print_cons_id_and_arity_to_strings(Indent + 1),
         OtherConsIdArityRep, OtherConsIdArityStrings),
     RevSubGoalPathSteps = [step_switch(CaseNum, no) | RevGoalPathSteps],
-    print_goal_to_strings(VarTable, Indent + 1, RevSubGoalPathSteps,
+    print_goal_to_strings(Info, Indent + 1, RevSubGoalPathSteps,
         GoalRep, HeadGoalString),
-    print_switch_to_strings(VarTable, Indent, RevGoalPathSteps, CaseNum + 1,
+    print_switch_to_strings(Info, Indent, RevGoalPathSteps, CaseNum + 1,
         CaseReps, yes, TailCasesStrings),
     Strings = DelimString ++ ConsIdArityString ++
         cord_list_to_cord(OtherConsIdArityStrings) ++ HeadGoalString ++
@@ -673,6 +712,87 @@ modulerep_search_proc(ModuleRep, ProcLab
     map.search(ModuleRep ^ mr_procs, ProcLabel, ProcRep).
 
 %----------------------------------------------------------------------------%
+%
+% Label goals with IDs.
+%
+
+label_goals(goal_id(LastIdPlus1 - 1), Map, !Goal) :-
+    label_goal(whole_body_goal, !Goal, counter.init(0), Counter,
+        map.init, Map),
+    allocate(LastIdPlus1, Counter, _).
+
+:- pred label_goal(containing_goal::in,
+    goal_rep(T)::in, goal_rep(goal_id)::out, counter::in, counter::out,
+    map(goal_id, containing_goal)::in, map(goal_id, containing_goal)::out)
+    is det.
+
+label_goal(ContainingGoal, !Goal, !Counter, !Map) :-
+    !.Goal = goal_rep(GoalExpr0, Detism, _),
+    allocate(GoalIdNum, !Counter),
+    GoalId = goal_id(GoalIdNum),
+    svmap.det_insert(GoalId, ContainingGoal, !Map),
+    (
+        GoalExpr0 = conj_rep(Conjs0),
+        map_foldl3(label_goal_wrapper((func(N) = step_conj(N)), GoalId),
+            Conjs0, Conjs, 1, _, !Counter, !Map),
+        GoalExpr = conj_rep(Conjs)
+    ;
+        GoalExpr0 = disj_rep(Disjs0),
+        map_foldl3(label_goal_wrapper((func(N) = step_conj(N)), GoalId),
+            Disjs0, Disjs, 1, _, !Counter, !Map),
+        GoalExpr = disj_rep(Disjs)
+    ;
+        GoalExpr0 = switch_rep(Var, CanFail, Cases0),
+        map_foldl3(label_case(GoalId), Cases0, Cases, 1, _, !Counter, !Map),
+        GoalExpr = switch_rep(Var, CanFail, Cases)
+    ;
+        GoalExpr0 = ite_rep(Cond0, Then0, Else0),
+        label_goal(containing_goal(GoalId, step_ite_cond), Cond0, Cond,
+            !Counter, !Map),
+        label_goal(containing_goal(GoalId, step_ite_then), Then0, Then,
+            !Counter, !Map),
+        label_goal(containing_goal(GoalId, step_ite_else), Else0, Else,
+            !Counter, !Map),
+        GoalExpr = ite_rep(Cond, Then, Else)
+    ;
+        GoalExpr0 = negation_rep(SubGoal0),
+        label_goal(containing_goal(GoalId, step_neg), SubGoal0, SubGoal,
+            !Counter, !Map),
+        GoalExpr = negation_rep(SubGoal)
+    ;
+        GoalExpr0 = scope_rep(SubGoal0, ScopeIsCut),
+        label_goal(containing_goal(GoalId, step_scope(ScopeIsCut)),
+            SubGoal0, SubGoal, !Counter, !Map),
+        GoalExpr = scope_rep(SubGoal, ScopeIsCut)
+    ;
+        GoalExpr0 = atomic_goal_rep(File, Line, BoundVars, AtomicGoal),
+        GoalExpr = atomic_goal_rep(File, Line, BoundVars, AtomicGoal)
+    ),
+    !:Goal = goal_rep(GoalExpr, Detism, GoalId).
+
+:- pred label_goal_wrapper(func(int) = goal_path_step, goal_id,
+    goal_rep(T), goal_rep(goal_id), int, int, counter, counter,
+    map(goal_id, containing_goal), map(goal_id, containing_goal)) is det.
+:- mode label_goal_wrapper(func(in) = out is det, in,
+    in, out, in, out, in, out, in, out) is det.
+
+label_goal_wrapper(MakePathStep, ParentGoalId, !Goal, !GoalNum, !Counter,
+        !Map) :-
+    label_goal(containing_goal(ParentGoalId, MakePathStep(!.GoalNum)),
+        !Goal, !Counter, !Map),
+    !:GoalNum = !.GoalNum + 1.
+
+:- pred label_case(goal_id::in, case_rep(T)::in, case_rep(goal_id)::out,
+    int::in, int::out, counter::in, counter::out,
+    containing_goal_map::in, containing_goal_map::out) is det.
+
+label_case(ParentGoalId, !Case, !CaseNum, !Counter, !Map) :-
+    !.Case = case_rep(MainConsId, OtherConsIds, Goal0),
+    label_goal_wrapper((func(N) = step_switch(N, no)), ParentGoalId,
+            Goal0, Goal, !CaseNum, !Counter, !Map),
+    !:Case = case_rep(MainConsId, OtherConsIds, Goal).
+
+%----------------------------------------------------------------------------%
 
 :- type inst_map
     --->    inst_map(
Index: deep_profiler/recursion_patterns.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/recursion_patterns.m,v
retrieving revision 1.12
diff -u -p -b -r1.12 recursion_patterns.m
--- deep_profiler/recursion_patterns.m	13 Jan 2011 04:44:28 -0000	1.12
+++ deep_profiler/recursion_patterns.m	17 Jan 2011 01:31:24 -0000
@@ -124,13 +124,13 @@ proc_get_recursion_type(Deep, ThisClique
     create_dynamic_procrep_coverage_report(Deep, PDPtr, MaybeCoverageReport),
     (
         MaybeCoverageReport = ok(CoverageReport),
-        ProcRep = CoverageReport ^ prci_proc_rep,
+        CoverageReport = procrep_coverage_info(_, ProcRep, CoverageArray),
         Goal = ProcRep ^ pr_defn ^ pdr_goal,
         proc_dynamic_paired_call_site_slots(Deep, PDPtr, Slots),
-        foldl(build_call_site_cost_and_callee_map(Deep),
+        foldl(build_dynamic_call_site_cost_and_callee_map(Deep),
             Slots, map.init, CallSitesMap),
-        goal_recursion_data(ThisClique, CallSitesMap, [],
-            Goal, RecursionData),
+        Info = recursion_analysis_info(ThisClique, CallSitesMap, CoverageArray),
+        goal_recursion_data(Info, [], Goal, RecursionData),
         recursion_data_to_recursion_type(ParentCalls, TotalCalls,
             RecursionData, RecursionType),
         MaybeRecursionType = ok(RecursionType)
@@ -281,19 +281,27 @@ single_rec_average_recursion_cost(BaseCo
 :- type recursion_error
     --->    re_unhandled_determinism(detism_rep).
 
+:- type recursion_analysis_info
+    --->    recursion_analysis_info(
+                rai_this_clique         :: clique_ptr,
+                rai_call_sites          ::
+                    map(reverse_goal_path, cost_and_callees),
+                rai_coverage_info       :: goal_attr_array(coverage_info)
+            ).
+
     % goal_recursion_data(RecursiveCallees, Goal, GoalPath,
     %   init_recursion_data, RecursionData)
     %
     % Compute RecursionData about Goal if RecursiveCalls are calls
     % that may eventually lead to Goal.
     %
-:- pred goal_recursion_data(clique_ptr::in,
-    map(reverse_goal_path, cost_and_callees)::in, list(goal_path_step)::in,
-    goal_rep(coverage_info)::in, recursion_data::out) is det.
+:- pred goal_recursion_data(recursion_analysis_info::in,
+    list(goal_path_step)::in, goal_rep(goal_id)::in, recursion_data::out)
+    is det.
 
-goal_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps, GoalRep,
-        !:RecursionData) :-
-    GoalRep = goal_rep(GoalExpr, Detism, CoverageInfo),
+goal_recursion_data(Info, RevGoalPathSteps, GoalRep, !:RecursionData) :-
+    GoalRep = goal_rep(GoalExpr, Detism, GoalId),
+    CoverageInfo = get_goal_attribute_det(Info ^ rai_coverage_info, GoalId),
     ( get_coverage_before(CoverageInfo, CallsPrime) ->
         Calls = CallsPrime
     ;
@@ -304,20 +312,20 @@ goal_recursion_data(ThisClique, CallSite
     ;
         (
             GoalExpr = conj_rep(Conjs),
-            conj_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps,
-                1, Conjs, !:RecursionData)
+            conj_recursion_data(Info, RevGoalPathSteps, 1, Conjs,
+                !:RecursionData)
         ;
             GoalExpr = disj_rep(Disjs),
-            disj_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps,
-                1, Disjs, !:RecursionData)
+            disj_recursion_data(Info, RevGoalPathSteps, 1, Disjs,
+                !:RecursionData)
         ;
             GoalExpr = switch_rep(_, _, Cases),
-            switch_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps,
-                1, Cases, float(Calls), Calls, !:RecursionData)
+            switch_recursion_data(Info, RevGoalPathSteps, 1, Cases,
+                float(Calls), Calls, !:RecursionData)
         ;
             GoalExpr = ite_rep(Cond, Then, Else),
-            ite_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps,
-                Cond, Then, Else, Calls, !:RecursionData)
+            ite_recursion_data(Info, RevGoalPathSteps, Cond, Then, Else,
+                Calls, !:RecursionData)
         ;
             (
                 GoalExpr = negation_rep(SubGoal),
@@ -326,13 +334,12 @@ goal_recursion_data(ThisClique, CallSite
                 GoalExpr = scope_rep(SubGoal, MaybeCut),
                 GoalPathStep = step_scope(MaybeCut)
             ),
-            goal_recursion_data(ThisClique, CallSiteMap,
-                [GoalPathStep | RevGoalPathSteps], SubGoal,
-                !:RecursionData)
+            goal_recursion_data(Info, [GoalPathStep | RevGoalPathSteps],
+                SubGoal, !:RecursionData)
         ;
             GoalExpr = atomic_goal_rep(_, _, _, AtomicGoalRep),
-            atomic_goal_recursion_data(ThisClique, CallSiteMap,
-                RevGoalPathSteps, AtomicGoalRep, !:RecursionData)
+            atomic_goal_recursion_data(Info, RevGoalPathSteps, AtomicGoalRep,
+                !:RecursionData)
         )
     ),
     (
@@ -351,17 +358,17 @@ goal_recursion_data(ThisClique, CallSite
             !RecursionData)
     ).
 
-:- pred conj_recursion_data(clique_ptr::in,
-    map(reverse_goal_path, cost_and_callees)::in, list(goal_path_step)::in,
-    int::in, list(goal_rep(coverage_info))::in, recursion_data::out) is det.
+:- pred conj_recursion_data(recursion_analysis_info::in,
+    list(goal_path_step)::in, int::in, list(goal_rep(goal_id))::in,
+    recursion_data::out) is det.
 
-conj_recursion_data(_, _, _, _, [], simple_recursion_data(0.0, 0)).
+conj_recursion_data(_, _, _, [], simple_recursion_data(0.0, 0)).
     % An empty conjunction is true, there is exactly one trivial path
     % through it with 0 recursive calls.
-conj_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps, ConjNum,
-        [Conj | Conjs], RecursionData) :-
-    goal_recursion_data(ThisClique, CallSiteMap,
-        [step_conj(ConjNum) | RevGoalPathSteps], Conj, ConjRecursionData),
+conj_recursion_data(Info, RevGoalPathSteps, ConjNum, [Conj | Conjs],
+        RecursionData) :-
+    goal_recursion_data(Info, [step_conj(ConjNum) | RevGoalPathSteps], Conj,
+        ConjRecursionData),
     (
         ConjRecursionData = proc_dead_code,
         % If the first conjunct is dead then the remaining ones will
@@ -371,8 +378,8 @@ conj_recursion_data(ThisClique, CallSite
     ;
         ConjRecursionData = recursion_data(_, _, _),
 
-        conj_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps,
-            ConjNum + 1, Conjs, ConjsRecursionData0),
+        conj_recursion_data(Info, RevGoalPathSteps, ConjNum + 1, Conjs,
+            ConjsRecursionData0),
         CanFail = detism_get_can_fail(Conj ^ goal_detism_rep),
         (
             CanFail = cannot_fail_rep,
@@ -384,8 +391,9 @@ conj_recursion_data(ThisClique, CallSite
             % branches into one branch that continues with the conjunction and
             % one that doesn't.
 
-            success_probability_from_coverage(Conj ^ goal_annotation,
-                ConjSuccessProb),
+            CoverageInfo = get_goal_attribute_det(Info ^ rai_coverage_info,
+                Conj ^ goal_annotation),
+            success_probability_from_coverage(CoverageInfo, ConjSuccessProb),
             recursion_data_and_probability(ConjSuccessProb,
                 ConjsRecursionData0, ConjsRecursionData),
 
@@ -399,17 +407,17 @@ conj_recursion_data(ThisClique, CallSite
         )
     ).
 
-:- pred disj_recursion_data(clique_ptr::in,
-    map(reverse_goal_path, cost_and_callees)::in, list(goal_path_step)::in,
-    int::in, list(goal_rep(coverage_info))::in, recursion_data::out) is det.
+:- pred disj_recursion_data(recursion_analysis_info::in,
+    list(goal_path_step)::in, int::in, list(goal_rep(goal_id))::in,
+    recursion_data::out) is det.
 
-disj_recursion_data(_, _, _, _, [], simple_recursion_data(0.0, 0)).
-disj_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps, DisjNum,
+disj_recursion_data(_, _, _, [], simple_recursion_data(0.0, 0)).
+disj_recursion_data(Info, RevGoalPathSteps, DisjNum,
         [Disj | Disjs], RecursionData) :-
     % Handle only semidet and committed-choice disjunctions, which cannot be
     % re-entered once a disjunct succeeds.
-    goal_recursion_data(ThisClique, CallSiteMap,
-        [step_disj(DisjNum) | RevGoalPathSteps], Disj, DisjRecursionData),
+    goal_recursion_data(Info, [step_disj(DisjNum) | RevGoalPathSteps], Disj,
+        DisjRecursionData),
     (
         DisjRecursionData = proc_dead_code,
         % If the first disjunct was never tried, then no other disjuncts will
@@ -417,14 +425,16 @@ disj_recursion_data(ThisClique, CallSite
         RecursionData = proc_dead_code
     ;
         DisjRecursionData = recursion_data(_, _, _),
-        success_probability_from_coverage(Disj ^ goal_annotation,
+        CoverageInfo = get_goal_attribute_det(Info ^ rai_coverage_info,
+            Disj ^ goal_annotation),
+        success_probability_from_coverage(CoverageInfo,
             DisjSuccessProb),
         DisjFailureProb = not_probability(DisjSuccessProb),
 
         % The code can branch here, either it tries the next disjuct, which we
         % represent as DisjsRecursionData, ...
-        disj_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps,
-            DisjNum + 1, Disjs, DisjsRecursionData0),
+        disj_recursion_data(Info, RevGoalPathSteps, DisjNum + 1, Disjs,
+            DisjsRecursionData0),
         recursion_data_and_probability(DisjFailureProb, DisjsRecursionData0,
             DisjsRecursionData),
 
@@ -457,31 +467,31 @@ success_probability_from_coverage(Covera
         unexpected($module, $pred, "expected complete coverage information")
     ).
 
-:- pred ite_recursion_data(clique_ptr::in,
-    map(reverse_goal_path, cost_and_callees)::in, list(goal_path_step)::in,
-    goal_rep(coverage_info)::in, goal_rep(coverage_info)::in,
-    goal_rep(coverage_info)::in, int::in, recursion_data::out) is det.
-
-ite_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps, Cond, Then, Else,
-        Calls, !:RecursionData) :-
-    goal_recursion_data(ThisClique, CallSiteMap,
-        [step_ite_cond | RevGoalPathSteps], Cond, CondRecursionData),
-    goal_recursion_data(ThisClique, CallSiteMap,
-        [step_ite_then | RevGoalPathSteps], Then, ThenRecursionData0),
-    goal_recursion_data(ThisClique, CallSiteMap,
-        [step_ite_else | RevGoalPathSteps], Else, ElseRecursionData0),
+:- pred ite_recursion_data(recursion_analysis_info::in,
+    list(goal_path_step)::in,
+    goal_rep(goal_id)::in, goal_rep(goal_id)::in, goal_rep(goal_id)::in,
+    int::in, recursion_data::out) is det.
+
+ite_recursion_data(Info, RevGoalPathSteps, Cond, Then, Else, Calls,
+        !:RecursionData) :-
+    goal_recursion_data(Info, [step_ite_cond | RevGoalPathSteps], Cond,
+        CondRecursionData),
+    goal_recursion_data(Info, [step_ite_then | RevGoalPathSteps], Then,
+        ThenRecursionData0),
+    goal_recursion_data(Info, [step_ite_else | RevGoalPathSteps], Else,
+        ElseRecursionData0),
 
     % Adjust the probabilities of executing the then and else branches.
-    (
-        get_coverage_before(Then ^ goal_annotation, ThenCalls),
-        get_coverage_before(Else ^ goal_annotation, ElseCalls)
-    ->
+    Coverage = Info ^ rai_coverage_info,
+    ThenCoverageInfo =
+        get_goal_attribute_det(Coverage, Then ^ goal_annotation),
+    ElseCoverageInfo =
+        get_goal_attribute_det(Coverage, Else ^ goal_annotation),
+    get_coverage_before_det(ThenCoverageInfo, ThenCalls),
+    get_coverage_before_det(ElseCoverageInfo, ElseCalls),
         CallsF = float(Calls),
         ThenProb = probable(float(ThenCalls) / CallsF),
-        ElseProb = probable(float(ElseCalls) / CallsF)
-    ;
-        unexpected($module, $pred, "couldn't retrive coverage information")
-    ),
+    ElseProb = probable(float(ElseCalls) / CallsF),
     recursion_data_and_probability(ThenProb,
         ThenRecursionData0, ThenRecursionData),
     recursion_data_and_probability(ElseProb,
@@ -495,24 +505,24 @@ ite_recursion_data(ThisClique, CallSiteM
         ElseRecursionData, !:RecursionData),
     merge_recursion_data_sequence(CondRecursionData, !RecursionData).
 
-:- pred switch_recursion_data(clique_ptr::in,
-    map(reverse_goal_path, cost_and_callees)::in, list(goal_path_step)::in,
-    int::in, list(case_rep(coverage_info))::in, float::in, int::in,
-    recursion_data::out) is det.
+:- pred switch_recursion_data(recursion_analysis_info::in,
+    list(goal_path_step)::in, int::in, list(case_rep(goal_id))::in,
+    float::in, int::in, recursion_data::out) is det.
 
-switch_recursion_data(_, _, _, _, [], TotalCalls, CallsRemaining,
+switch_recursion_data(_, _, _, [], TotalCalls, CallsRemaining,
         RecursionData) :-
     % Can fail switches will have a nonzero probability of reaching this case.
     FailProb = probable(float(CallsRemaining) / TotalCalls),
     RecursionData0 = simple_recursion_data(0.0, 0),
     recursion_data_and_probability(FailProb, RecursionData0, RecursionData).
-switch_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps, CaseNum,
-        [Case | Cases], TotalCalls, CallsRemaining, RecursionData) :-
+switch_recursion_data(Info, RevGoalPathSteps, CaseNum, [Case | Cases],
+        TotalCalls, CallsRemaining, RecursionData) :-
     Case = case_rep(_, _, Goal),
-    goal_recursion_data(ThisClique, CallSiteMap,
-        [step_switch(CaseNum, no) | RevGoalPathSteps], Goal,
-        CaseRecursionData0),
-    ( get_coverage_before(Goal ^ goal_annotation, CallsPrime) ->
+    goal_recursion_data(Info, [step_switch(CaseNum, no) | RevGoalPathSteps],
+        Goal, CaseRecursionData0),
+    CoverageInfo = get_goal_attribute_det(Info ^ rai_coverage_info,
+        Goal ^ goal_annotation),
+    ( get_coverage_before(CoverageInfo, CallsPrime) ->
         Calls = CallsPrime
     ;
         unexpected($module, $pred, "expected coverage information")
@@ -520,17 +530,16 @@ switch_recursion_data(ThisClique, CallSi
     CaseProb = probable(float(Calls) / TotalCalls),
     recursion_data_and_probability(CaseProb, CaseRecursionData0,
         CaseRecursionData),
-    switch_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps, CaseNum+1,
+    switch_recursion_data(Info, RevGoalPathSteps, CaseNum+1,
         Cases, TotalCalls, CallsRemaining - Calls, CasesRecursionData),
     merge_recursion_data_after_branch(CaseRecursionData, CasesRecursionData,
         RecursionData).
 
-:- pred atomic_goal_recursion_data(clique_ptr::in,
-    map(reverse_goal_path, cost_and_callees)::in, list(goal_path_step)::in,
-    atomic_goal_rep::in, recursion_data::out) is det.
+:- pred atomic_goal_recursion_data(recursion_analysis_info::in,
+    list(goal_path_step)::in, atomic_goal_rep::in, recursion_data::out) is det.
 
-atomic_goal_recursion_data(ThisClique, CallSiteMap, RevGoalPathSteps,
-        AtomicGoal, RecursionData) :-
+atomic_goal_recursion_data(Info, RevGoalPathSteps, AtomicGoal, RecursionData)
+        :-
     (
         % All these things have trivial cost except for foreign code whose cost
         % is unknown (which because it doesn't contribute to the cost of the
@@ -554,6 +563,7 @@ atomic_goal_recursion_data(ThisClique, C
         ),
 
         % Get the cost of the call.
+        Info = recursion_analysis_info(ThisClique, CallSiteMap, _),
         map.lookup(CallSiteMap, rgp(RevGoalPathSteps), CostAndCallees),
         ( cost_and_callees_is_recursive(ThisClique, CostAndCallees) ->
             % Cost will be 1.0 for for each call to recursive calls but we
Index: deep_profiler/report.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/report.m,v
retrieving revision 1.30
diff -u -p -b -r1.30 report.m
--- deep_profiler/report.m	13 Jan 2011 00:36:55 -0000	1.30
+++ deep_profiler/report.m	17 Jan 2011 01:31:24 -0000
@@ -415,7 +415,8 @@
 :- type procrep_coverage_info
     --->    procrep_coverage_info(
                 prci_proc                   :: proc_static_ptr,
-                prci_proc_rep               :: proc_rep(coverage_info)
+                prci_proc_rep               :: proc_rep(goal_id),
+                prci_coverage_array         :: goal_attr_array(coverage_info)
             ).
 
 :- type proc_callers_report
Index: deep_profiler/var_use_analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/var_use_analysis.m,v
retrieving revision 1.11
diff -u -p -b -r1.11 var_use_analysis.m
--- deep_profiler/var_use_analysis.m	13 Jan 2011 00:36:55 -0000	1.11
+++ deep_profiler/var_use_analysis.m	17 Jan 2011 01:31:24 -0000
@@ -124,21 +124,15 @@
 
 %-----------------------------------------------------------------------------%
 
-:- typeclass goal_annotation_with_coverage(T) where [
-        (func get_coverage(goal_rep(T)) = coverage_info)
-    ].
-
-:- instance goal_annotation_with_coverage(coverage_info).
-
     % Find the first use of a variable in an arbitrary goal.
     %
 :- pred var_first_use(clique_ptr::in,
     map(reverse_goal_path, cost_and_callees)::in,
     map(reverse_goal_path, cs_cost_csq)::in,
+    goal_attr_array(coverage_info)::in,
     recursion_type::in(recursion_type_known_costs), recursion_depth::in,
-    goal_rep(T)::in, reverse_goal_path::in, float::in, var_rep::in,
-    var_use_options::in, var_use_info::out) is det
-    <= goal_annotation_with_coverage(T).
+    goal_rep(goal_id)::in, reverse_goal_path::in, float::in, var_rep::in,
+    var_use_options::in, var_use_info::out) is det.
 
 %-----------------------------------------------------------------------------%
 
@@ -340,7 +334,8 @@ proc_dynamic_var_use_info(CliquePtr, PDP
     create_dynamic_procrep_coverage_report(Deep, PDPtr, MaybeProcrepCoverage),
     (
         MaybeProcrepCoverage = ok(ProcrepCoverage),
-        ProcDefn = ProcrepCoverage ^ prci_proc_rep ^ pr_defn,
+        ProcrepCoverage = procrep_coverage_info(_, ProcRep, CoverageArray),
+        ProcDefn = ProcRep ^ pr_defn,
         HeadVars = ProcDefn ^ pdr_head_vars,
         ( index0(HeadVars, ArgNum, head_var_rep(Var, Mode)) ->
             var_mode_to_var_use_type(Mode, ComputedUse),
@@ -359,7 +354,7 @@ proc_dynamic_var_use_info(CliquePtr, PDP
 
             % Prepare callsite information.
             proc_dynamic_paired_call_site_slots(Deep, PDPtr, Slots),
-            foldl(build_call_site_cost_and_callee_map(Deep),
+            foldl(build_dynamic_call_site_cost_and_callee_map(Deep),
                 Slots, map.init, CallSiteCostMap),
 
             % We're following a recursive call, therefore we descend one level.
@@ -370,7 +365,7 @@ proc_dynamic_var_use_info(CliquePtr, PDP
 
             % Do the actual computation.
             Goal = ProcDefn ^ pdr_goal,
-            goal_var_first_use_wrapper(CliquePtr, CallStack,
+            goal_var_first_use_wrapper(CliquePtr, CallStack, CoverageArray,
                 CallSiteCostMap, RecursiveCallSiteCostMap, RecursionType,
                 Depth, Goal, ProcCost, Var, VarUseOptions, VarUseInfo),
             MaybeVarUseInfo = ok(VarUseInfo)
@@ -408,6 +403,7 @@ proc_dynamic_var_use_info(CliquePtr, PDP
                                                 cost_and_callees),
                 fui_rec_call_site_map   :: map(reverse_goal_path,
                                                 cs_cost_csq),
+                fui_coverage_array      :: goal_attr_array(coverage_info),
                 fui_var                 :: var_rep,
                 fui_var_use_opts        :: var_use_options,
 
@@ -422,7 +418,7 @@ proc_dynamic_var_use_info(CliquePtr, PDP
 
 :- inst var_first_use_static_info
     --->    var_first_use_static_info(
-                ground, ground, ground, ground, ground, ground,
+                ground, ground, ground, ground, ground, ground, ground,
                 recursion_type_known_costs,
                 ground
             ).
@@ -436,15 +432,15 @@ proc_dynamic_var_use_info(CliquePtr, PDP
     % follow call the calls seen during profiling and aggregate their variable
     % use information based on how often they are called from that call site.
     %
-:- pred goal_var_first_use(list(goal_path_step)::in, goal_rep(T)::in,
+:- pred goal_var_first_use(list(goal_path_step)::in, goal_rep(goal_id)::in,
     var_first_use_static_info::in(var_first_use_static_info), float::in,
-    float::out, found_first_use::out) is det
-    <= goal_annotation_with_coverage(T).
+    float::out, found_first_use::out) is det.
 
 goal_var_first_use(RevGoalPathSteps, Goal, StaticInfo, !CostSoFar,
         FoundFirstUse) :-
     Goal = goal_rep(GoalExpr, Detism, _),
-    Coverage = get_coverage(Goal),
+    CoverageArray = StaticInfo ^ fui_coverage_array,
+    Coverage = get_goal_attribute_det(CoverageArray, Goal ^ goal_annotation),
     (
         % Do not bother exploring this goal if it is never entered.  Or never
         % finishes and we're looking for a production.
@@ -536,8 +532,8 @@ goal_var_first_use(RevGoalPathSteps, Goa
 call_var_first_use(AtomicGoal, BoundVars, RevGoalPathSteps, StaticInfo,
         CostSoFar, NextCostSoFar, FoundFirstUse) :-
     StaticInfo = var_first_use_static_info(CliquePtr, CostMap,
-        RecCostMap, Var, VarUseOptions, _CallStack, _RecursionType,
-        _MaybeCurDepth),
+        RecCostMap, _CoverageArray, Var, VarUseOptions, _CallStack,
+        _RecursionType, _MaybeCurDepth),
     VarUseType = VarUseOptions ^ vuo_var_use_type,
     RevGoalPath = rgp(RevGoalPathSteps),
     map.lookup(CostMap, RevGoalPath, CostAndCallees),
@@ -645,7 +641,8 @@ consume_ho_arg(method_call_rep(Var, _, _
 
 call_args_first_use(Args, Cost, StaticInfo, CostAndCallees, Time) :-
     StaticInfo = var_first_use_static_info(CliquePtr, _CostMap,
-        _RecCostMap, Var, VarUseOptions, CallStack, RecursionType, CurDepth),
+        _RecCostMap, _CoverageArray, Var, VarUseOptions, CallStack,
+        RecursionType, CurDepth),
     VarUseType = VarUseOptions ^ vuo_var_use_type,
     HigherOrder = CostAndCallees ^ cac_call_site_is_ho,
     Callees = CostAndCallees ^ cac_callees,
@@ -721,10 +718,9 @@ atomic_trivial_var_first_use(AtomicGoal,
     % an execution order, namely disjunctions and if-then-elses.
     %
 :- pred conj_var_first_use(list(goal_path_step)::in, int::in,
-    list(goal_rep(T))::in,
+    list(goal_rep(goal_id))::in,
     var_first_use_static_info::in(var_first_use_static_info),
-    float::in, float::out, found_first_use::out) is det
-    <= goal_annotation_with_coverage(T).
+    float::in, float::out, found_first_use::out) is det.
 
 conj_var_first_use(_, _, [], _, !Cost, have_not_found_first_use).
 conj_var_first_use(RevGoalPathSteps, ConjNum, [Conj | Conjs], StaticInfo,
@@ -745,10 +741,10 @@ conj_var_first_use(RevGoalPathSteps, Con
         FoundFirstUse = TailFoundFirstUse
     ).
 
-:- pred disj_var_first_use(list(goal_path_step)::in, list(goal_rep(T))::in,
-    detism_rep::in, var_first_use_static_info::in(var_first_use_static_info),
-    float::in, float::out, found_first_use::out) is det
-    <= goal_annotation_with_coverage(T).
+:- pred disj_var_first_use(list(goal_path_step)::in,
+    list(goal_rep(goal_id))::in, detism_rep::in,
+    var_first_use_static_info::in(var_first_use_static_info),
+    float::in, float::out, found_first_use::out) is det.
 
 disj_var_first_use(RevGoalPathSteps, Disjuncts, Detism, StaticInfo,
         !CostSoFar, FoundFirstUse) :-
@@ -781,15 +777,15 @@ disj_var_first_use(RevGoalPathSteps, Dis
     ).
 
 :- pred disj_var_first_use_2(list(goal_path_step)::in, int::in,
-    list(goal_rep(T))::in,
+    list(goal_rep(goal_id))::in,
     var_first_use_static_info::in(var_first_use_static_info),
-    float::in, float::out, found_first_use::out) is det
-    <= goal_annotation_with_coverage(T).
+    float::in, float::out, found_first_use::out) is det.
 
 disj_var_first_use_2(_, _, [], _, !CostSoFar, have_not_found_first_use).
 disj_var_first_use_2(RevGoalPathSteps, DisjNum, [Disj | Disjs], StaticInfo,
         !CostSoFar, FoundFirstUse) :-
     VarUseType = StaticInfo ^ fui_var_use_opts ^ vuo_var_use_type,
+    CoverageArray = StaticInfo ^ fui_coverage_array,
     goal_var_first_use([step_disj(DisjNum) | RevGoalPathSteps], Disj,
         StaticInfo, !CostSoFar, HeadFoundFirstUse),
     disj_var_first_use_2(RevGoalPathSteps, DisjNum + 1, Disjs, StaticInfo,
@@ -820,7 +816,9 @@ disj_var_first_use_2(RevGoalPathSteps, D
             ),
             % Use a weighted average to reflect the likely success of the first
             % disjunct.
-            ( get_coverage_before(get_coverage(Disj), HeadCount) ->
+            DisjCoverage =
+                get_goal_attribute_det(CoverageArray, Disj ^ goal_annotation),
+            ( get_coverage_before(DisjCoverage, HeadCount) ->
                 HeadWeight = float(HeadCount)
             ;
                 unexpected($module, $pred,
@@ -831,7 +829,8 @@ disj_var_first_use_2(RevGoalPathSteps, D
                 TailWeight = 0.0
             ;
                 Disjs = [FirstTailDisj | _],
-                FirstTailCoverage = get_coverage(FirstTailDisj),
+                FirstTailCoverage = get_goal_attribute_det(CoverageArray,
+                    FirstTailDisj ^ goal_annotation),
                 ( get_coverage_before(FirstTailCoverage, TailCount) ->
                     TailWeight = float(TailCount)
                 ;
@@ -846,10 +845,9 @@ disj_var_first_use_2(RevGoalPathSteps, D
     ).
 
 :- pred switch_var_first_use(list(goal_path_step)::in, var_rep::in,
-    list(case_rep(T))::in,
+    list(case_rep(goal_id))::in,
     var_first_use_static_info::in(var_first_use_static_info),
-    float::in, float::out, found_first_use::out) is det
-    <= goal_annotation_with_coverage(T).
+    float::in, float::out, found_first_use::out) is det.
 
 switch_var_first_use(RevGoalPathSteps, SwitchedOnVar, Cases, StaticInfo,
         CostBeforeSwitch, CostAfterSwitch, FoundFirstUse) :-
@@ -884,9 +882,8 @@ switch_var_first_use(RevGoalPathSteps, S
 
 :- pred switch_var_first_use_2(list(goal_path_step)::in, int::in,
     var_first_use_static_info::in(var_first_use_static_info),
-    list(case_rep(T))::in, list(float)::out, float::in,
-    list(float)::out, list(found_first_use)::out)
-    is det <= goal_annotation_with_coverage(T).
+    list(case_rep(goal_id))::in, list(float)::out, float::in,
+    list(float)::out, list(found_first_use)::out) is det.
 
 switch_var_first_use_2(_, _, _, [], [], _, [], []).
 switch_var_first_use_2(RevGoalPathSteps, CaseNum, StaticInfo, [Case | Cases],
@@ -897,29 +894,27 @@ switch_var_first_use_2(RevGoalPathSteps,
     Case = case_rep(_, _, Goal),
     goal_var_first_use([step_switch(CaseNum, no) | RevGoalPathSteps],
         Goal, StaticInfo, Cost0, Cost, FoundFirstUse),
-    ( get_coverage_before(get_coverage(Goal), BeforeCount) ->
-        Weight = float(BeforeCount)
-    ;
-        unexpected($module, $pred, "unknown coverage before switch case")
-    ).
+    Coverage = get_goal_attribute_det(StaticInfo ^ fui_coverage_array,
+        Goal ^ goal_annotation),
+    get_coverage_before_det(Coverage, BeforeCount),
+    Weight = float(BeforeCount).
 
 :- pred ite_var_first_use(list(goal_path_step)::in,
-    goal_rep(T)::in, goal_rep(T)::in, goal_rep(T)::in,
+    goal_rep(goal_id)::in, goal_rep(goal_id)::in, goal_rep(goal_id)::in,
     var_first_use_static_info::in(var_first_use_static_info),
     float::in, float::out, found_first_use::out)
-    is det <= goal_annotation_with_coverage(T).
+    is det.
 
 ite_var_first_use(RevGoalPathSteps, Cond, Then, Else, StaticInfo,
         !CostSoFar, FoundFirstUse) :-
-    (
-        get_coverage_before(get_coverage(Then), CountBeforeThen),
-        get_coverage_before(get_coverage(Else), CountBeforeElse)
-    ->
-        Weights = [float(CountBeforeThen), float(CountBeforeElse)]
-    ;
-        unexpected($module, $pred,
-            "incomplete coverage information for if-then-else branches")
-    ),
+    CoverageArray = StaticInfo ^ fui_coverage_array,
+    ThenCoverage =
+        get_goal_attribute_det(CoverageArray, Then ^ goal_annotation),
+    get_coverage_before_det(ThenCoverage, CountBeforeThen),
+    ElseCoverage =
+        get_goal_attribute_det(CoverageArray, Else ^ goal_annotation),
+    get_coverage_before_det(ElseCoverage, CountBeforeElse),
+    Weights = [float(CountBeforeThen), float(CountBeforeElse)],
     RevCondGoalPathSteps = [step_ite_cond | RevGoalPathSteps],
     RevThenGoalPathSteps = [step_ite_then | RevGoalPathSteps],
     RevElseGoalPathSteps = [step_ite_else | RevGoalPathSteps],
@@ -977,33 +972,31 @@ ffu_to_float(_, found_first_use(CostBefo
 %----------------------------------------------------------------------------%
 
 :- pred goal_var_first_use_wrapper(clique_ptr::in, set(proc_dynamic_ptr)::in,
+    goal_attr_array(coverage_info)::in,
     map(reverse_goal_path, cost_and_callees)::in,
     map(reverse_goal_path, cs_cost_csq)::in,
     recursion_type::in(recursion_type_known_costs), recursion_depth::in,
-    goal_rep(coverage_info)::in, float::in, var_rep::in,
+    goal_rep(goal_id)::in, float::in, var_rep::in,
     var_use_options::in, var_use_info::out) is det.
 
-goal_var_first_use_wrapper(CliquePtr, CallStack, CallSiteMap,
+goal_var_first_use_wrapper(CliquePtr, CallStack, CoverageArray, CallSiteMap,
         RecursiveCallSiteMap, RT, CurDepth, Goal, ProcCost, Var,
         VarUseOptions, VarUseInfo) :-
     goal_var_first_use([], Goal,
         var_first_use_static_info(CliquePtr, CallSiteMap, RecursiveCallSiteMap,
-            Var, VarUseOptions, CallStack, RT, CurDepth),
+            CoverageArray, Var, VarUseOptions, CallStack, RT, CurDepth),
         0.0, _Cost, FoundFirstUse),
     VarUseType = VarUseOptions ^ vuo_var_use_type,
     found_first_use_to_use_info(FoundFirstUse, ProcCost, VarUseType,
         VarUseInfo).
 
-:- instance goal_annotation_with_coverage(coverage_info) where [
-    (get_coverage(Goal) = Goal ^ goal_annotation)
-].
-
-var_first_use(CliquePtr, CallSiteMap, RecursiveCallSiteMap, RT, CurDepth,
-        Goal, RevGoalPath, Cost, Var, VarUseOptions, VarUseInfo) :-
+var_first_use(CliquePtr, CallSiteMap, RecursiveCallSiteMap, CoverageArray,
+        RT, CurDepth, Goal, RevGoalPath, Cost, Var, VarUseOptions,
+        VarUseInfo) :-
     RevGoalPath = rgp(RevGoalPathSteps),
     goal_var_first_use(RevGoalPathSteps, Goal,
         var_first_use_static_info(CliquePtr, CallSiteMap, RecursiveCallSiteMap,
-            Var, VarUseOptions, set.init, RT, CurDepth),
+            CoverageArray, Var, VarUseOptions, set.init, RT, CurDepth),
         0.0, _, FoundFirstUse),
     VarUseType = VarUseOptions ^ vuo_var_use_type,
     found_first_use_to_use_info(FoundFirstUse, Cost, VarUseType, VarUseInfo).
Index: mdbcomp/mdbcomp.goal_path.m
===================================================================
RCS file: /home/mercury1/repository/mercury/mdbcomp/mdbcomp.goal_path.m,v
retrieving revision 1.1
diff -u -p -b -r1.1 mdbcomp.goal_path.m
--- mdbcomp/mdbcomp.goal_path.m	14 Jan 2011 04:07:55 -0000	1.1
+++ mdbcomp/mdbcomp.goal_path.m	17 Jan 2011 01:31:48 -0000
@@ -51,6 +51,7 @@
 :- module mdbcomp.goal_path.
 :- interface.
 
+:- import_module array.
 :- import_module bimap.
 :- import_module char.
 :- import_module list.
@@ -250,12 +251,47 @@
     goal_reverse_path_bimap.
 
 %-----------------------------------------------------------------------------%
+
+:- type goal_attr_array(T)
+    --->    goal_attr_array(array(maybe(T))).
+
+    % This isn't really unique, see the commends at the type of library/array.m
+    %
+:- inst uniq_goal_attr_array
+    --->    goal_attr_array(uniq_array).
+
+:- mode gaa_di == di(uniq_goal_attr_array).
+:- mode gaa_uo == out(uniq_goal_attr_array).
+
+    % create_goal_id_array(LastGoalId) = Array.
+    %
+    % Create an array of the correct size to label all the goals up to and
+    % including LastGoalId.
+    %
+:- func create_goal_id_array(goal_id) = goal_attr_array(T).
+:- mode create_goal_id_array(in) = gaa_uo is det.
+
+    % update_goal_attribute(GoalId, Attribute, !Array),
+    %
+    % Make Attirubte the new attribute for GoalId in !:Array.
+    %
+:- pred update_goal_attribute(goal_id::in, T::in,
+    goal_attr_array(T)::gaa_di, goal_attr_array(T)::gaa_uo) is det.
+
+    % get_goal_attribute(Arra, GoalId) = Attribute.
+    %
+    % Get a goal attribute.
+    %
+:- func get_goal_attribute_det(goal_attr_array(T), goal_id) = T.
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- implementation.
 
 :- import_module assoc_list.
 :- import_module cord.
+:- import_module int.
 :- import_module pair.
 :- import_module require.
 :- import_module string.
@@ -524,4 +560,22 @@ create_reverse_goal_path_bimap_2([Head |
     create_reverse_goal_path_bimap_2(Tail, !ReverseGoalPathBiMap).
 
 %-----------------------------------------------------------------------------%
+
+create_goal_id_array(goal_id(LastGoalIdNum)) =
+    goal_attr_array(array.init(LastGoalIdNum + 1, no)).
+
+update_goal_attribute(goal_id(Index), Value, goal_attr_array(!.Array),
+        goal_attr_array(!:Array)) :-
+    array.svset(Index, yes(Value), !Array).
+
+get_goal_attribute_det(goal_attr_array(Array), goal_id(Index)) = Attr :-
+    MaybeAttr = array.lookup(Array, Index),
+    (
+        MaybeAttr = yes(Attr)
+    ;
+        MaybeAttr = no,
+        unexpected($module, $pred, "Goal attribute array slot empty")
+    ).
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 489 bytes
Desc: Digital signature
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20110117/d9234293/attachment.sig>


More information about the reviews mailing list