[m-rev.] for post-commit review: Coverage Profiling completed.

Paul Bone pbone at csse.unimelb.edu.au
Thu Sep 25 23:33:59 AEST 2008


For post-commit review by Zoltan.

Estimated hours taken: 10 
Branches: main

Re-write coverage profiling transformation and propagation algorithm.  The code
in the profiler and in the compiler both now traverse a procedure in the same
way.  This way the coverage profiling transformation knows if the coverage
propagation algorithm will be able to infer the coverage at a given point in
the program or if it needs a coverage point inserted.

compiler/deep_profiling.m:
	As above.
	Print out status messages before performing deep profiling on each
	procedure when the verbose option is enabled..

compiler/options.m:
	The first pass of the coverage profiling transformation has been disabled
	since it's not currently used by the second pass.

compiler/mercury_compile.m:
	Conform to changes in compiler/deep_profiling.m

compiler/Mercury.options:
	Disable the work around for bug 85 since it is no longer triggered by
	deep_profiling.m.

deep_profiler/program_representation_utils.m:
	As above.
	Fix a bug when printing out a scope goal in the procedure representation.

Index: compiler/Mercury.options
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/Mercury.options,v
retrieving revision 1.38
diff -u -p -b -r1.38 Mercury.options
--- compiler/Mercury.options	23 Sep 2008 01:26:10 -0000	1.38
+++ compiler/Mercury.options	25 Sep 2008 12:42:05 -0000
@@ -60,9 +60,6 @@ MCFLAGS-analysis = --no-common-struct
 # mmc -r analysis.file.c -s asm_fast.gc -O4 --intermodule-optimisation
 MCFLAGS-analysis.file = --no-optimise-higher-order
 
-# Workaround for bug 85 in Mantis.
-MCFLAGS-ll_backend.deep_profiling = -O2
-
 # This works around bug 32 in Mantis.
 MCFLAGS-check_hlds.check_typeclass = --no-loop-invariants
 
Index: compiler/deep_profiling.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/deep_profiling.m,v
retrieving revision 1.86
diff -u -p -b -r1.86 deep_profiling.m
--- compiler/deep_profiling.m	20 Sep 2008 11:38:03 -0000	1.86
+++ compiler/deep_profiling.m	25 Sep 2008 13:31:02 -0000
@@ -20,10 +20,12 @@
 
 :- import_module hlds.hlds_module.
 
+:- import_module io.
+
 %-----------------------------------------------------------------------------%
 
-:- pred apply_deep_profiling_transformation(module_info::in, module_info::out)
-    is det.
+:- pred apply_deep_profiling_transformation(module_info::in, module_info::out,
+    io::di, io::uo) is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -36,11 +38,13 @@
 :- import_module hlds.code_model.
 :- import_module hlds.goal_util.
 :- import_module hlds.hlds_goal.
+:- import_module hlds.hlds_out.
 :- import_module hlds.hlds_pred.
 :- import_module hlds.hlds_rtti.
 :- import_module hlds.instmap.
 :- import_module hlds.pred_table.
 :- import_module libs.compiler_util.
+:- import_module libs.file_util.
 :- import_module libs.globals.
 :- import_module libs.options.
 :- import_module mdbcomp.prim_data.
@@ -69,7 +73,7 @@
 
 %-----------------------------------------------------------------------------%
 
-apply_deep_profiling_transformation(!ModuleInfo) :-
+apply_deep_profiling_transformation(!ModuleInfo, !IO) :-
     module_info_get_globals(!.ModuleInfo, Globals),
     globals.lookup_bool_option(Globals, deep_profile_tail_recursion,
         TailRecursion),
@@ -82,7 +86,8 @@ apply_deep_profiling_transformation(!Mod
     module_info_predids(PredIds, !ModuleInfo),
     module_info_get_predicate_table(!.ModuleInfo, PredTable0),
     predicate_table_get_preds(PredTable0, PredMap0),
-    list.foldl(transform_predicate(!.ModuleInfo), PredIds, PredMap0, PredMap), 
+    list.foldl2(transform_predicate(!.ModuleInfo), PredIds, PredMap0, PredMap,
+        !IO), 
     predicate_table_set_preds(PredMap, PredTable0, PredTable),
     module_info_set_predicate_table(PredTable, !ModuleInfo).
 
@@ -444,21 +449,21 @@ figure_out_rec_call_numbers_in_case_list
 %-----------------------------------------------------------------------------%
 
 :- pred transform_predicate(module_info::in, pred_id::in,
-    pred_table::in, pred_table::out) is det.
+    pred_table::in, pred_table::out, io::di, io::uo) is det.
 
-transform_predicate(ModuleInfo, PredId, PredMap0, PredMap) :-
+transform_predicate(ModuleInfo, PredId, PredMap0, PredMap, !IO) :-
     map.lookup(PredMap0, PredId, PredInfo0),
     ProcIds = pred_info_non_imported_procids(PredInfo0),
     pred_info_get_procedures(PredInfo0, ProcTable0),
-    list.foldl(maybe_transform_procedure(ModuleInfo, PredId),
-        ProcIds, ProcTable0, ProcTable),
+    list.foldl2(maybe_transform_procedure(ModuleInfo, PredId),
+        ProcIds, ProcTable0, ProcTable, !IO),
     pred_info_set_procedures(ProcTable, PredInfo0, PredInfo),
     map.det_update(PredMap0, PredId, PredInfo, PredMap).
 
 :- pred maybe_transform_procedure(module_info::in, pred_id::in, proc_id::in,
-    proc_table::in, proc_table::out) is det.
+    proc_table::in, proc_table::out, io::di, io::uo) is det.
 
-maybe_transform_procedure(ModuleInfo, PredId, ProcId, !ProcTable) :-
+maybe_transform_procedure(ModuleInfo, PredId, ProcId, !ProcTable, !IO) :-
     map.lookup(!.ProcTable, ProcId, ProcInfo0),
     proc_info_get_goal(ProcInfo0, Goal0),
     PredModuleName = predicate_module(ModuleInfo, PredId),
@@ -476,6 +481,12 @@ maybe_transform_procedure(ModuleInfo, Pr
     ->
         true
     ;
+        module_info_get_globals(ModuleInfo, Globals), 
+        globals.lookup_bool_option(Globals, verbose, Verbose),
+        ProcName = pred_proc_id_pair_to_string(ModuleInfo, PredId, ProcId),
+        maybe_write_string(Verbose, 
+            string.format("Deep profiling: %s\n", [s(ProcName)]), 
+            !IO),
         deep_prof_transform_proc(ModuleInfo, proc(PredId, ProcId),
             ProcInfo0, ProcInfo),
         map.det_update(!.ProcTable, ProcId, ProcInfo, !:ProcTable)
@@ -2008,7 +2019,7 @@ coverage_prof_transform_goal(ModuleInfo,
     ;
         CoverageProfilingOptions ^ cpo_use_2pass = no
     ),
-    coverage_prof_second_pass_goal(!Goal, coverage_after_known, _,
+    coverage_prof_second_pass_goal(!Goal, coverage_before_known, _,
         CoverageInfo0, CoverageInfo, _),
     CoverageInfo ^ ci_coverage_points = CoveragePointsMap,
     CoverageInfo ^ ci_var_info = !:VarInfo,
@@ -2017,140 +2028,42 @@ coverage_prof_transform_goal(ModuleInfo,
     % Transform a goal for coverage profiling. This is the second pass of
     % the coverage profiling transformation, and it consists of several steps.
     %
-    % If the first pass has been performed then we collect the relevant
-    % information from the goal_info structure.
+    % Step 1: Apply transformation recursively.
     %
-    % Step 1: Make a decision whether to insert a coverage point after this
-    % goal or not.
+    % Step 2: Consider inserting a coverage point after this goal to measure
+    % how many times it succeeds.
     %
-    % Step 2: Determine if coverage information is known for goals that
-    % execute before this goal completes. This includes goals before this
-    % goal (such as within a conjunction) or goals within this goal.
-    % Information collected in the first pass is used here.
-    %
-    % Step 3: Transform inner goals if this goal is non-atomic.
-    %
-    % Step 4: Insert a coverage point after this goal if we decided to do so
-    % at step 1.  This is done here after any inner goals have been
-    % transformed.
+    % Step 3: Insert the coverage point if we decided to earlier.
     %
 :- pred coverage_prof_second_pass_goal(hlds_goal::in, hlds_goal::out,
-    coverage_after_known::in, coverage_after_known::out,
+    coverage_before_known::in, coverage_before_known::out,
     proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
 
 coverage_prof_second_pass_goal(Goal0, Goal,
-        CoverageAfterKnown0, NextCoverageAfterKnown, !Info, AddedImpurity) :-
+        CoverageBeforeKnown, NextCoverageBeforeKnown, !Info, AddedImpurity) :-
     Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
     Detism = GoalInfo0 ^ goal_info_get_determinism,
     CPOptions = !.Info ^ ci_coverage_profiling_opts,
+    GoalPath = goal_info_get_goal_path(GoalInfo0),
 
-    % Depending on command line arguments first pass information may or may not
-    % be available, if it is not available, we assume semi-sensible defaults.
-    DPInfo = goal_info_get_dp_info(GoalInfo0),
-    DPInfo = dp_goal_info(IsMDProfInst, MaybeDPCoverageInfo),
-    (
-        MaybeDPCoverageInfo =
-            yes(dp_coverage_goal_info(GoalTrivial, GoalPortCountsCoverageAfter))
-    ;
-        MaybeDPCoverageInfo = no,
-
-        % XXX: Zoltan says;
-        % Is this the best default you can get? You should be able to do
-        % better for goals like unifications.
-        %
-        % pbone: I agree.  Idealy we should get more accurate information for
-        % atomic goals and fall back to these defaults for any other goal.
-
-        GoalTrivial = goal_is_nontrivial,
-        GoalPortCountsCoverageAfter = no_port_counts_give_coverage_after
-    ),
-    
-    (
-        GoalPortCountsCoverageAfter = port_counts_give_coverage_after,
-        CoverageAfterKnown1 = coverage_after_known
-    ;
-        GoalPortCountsCoverageAfter = no_port_counts_give_coverage_after,
-        CoverageAfterKnown1 = CoverageAfterKnown0 
-    ),
-
-    % Step 1.
-    %
-    % Consider inserting a coverage point after this goal to measure how
-    % many solutions it may have.
-    (
         (   
-            % Never insert coverage points on goals that are part of the deep
-            % profiling instrumentation.
-            IsMDProfInst = goal_is_mdprof_inst
-        ;
-            % We already have execution counts for the program point after this
-            % goal; adding a counter would be redundant.
-            CoverageAfterKnown1 = coverage_after_known
-        ;
-            % We don't need to know the execution count of this goal, since
-            % it is too cheap to matter.
-            GoalTrivial = goal_is_trivial
-        ;
-            % Never insert coverage points after conjunctions; wait until
-            % the algorithm recurses to inside the conjunction and make a
-            % better decision about the last conjunct. This can reduce the
-            % number of coverage points inserted in some cases.
-            GoalExpr0 = conj(plain_conj, _)
-
-            % We haven't yet thought about whether or not we should treat
-            % parallel conjunctions the same way.
-        )
+        IsMDProfInst = goal_is_not_mdprof_inst,
+        CoverageBeforeKnown = coverage_before_unknown
     ->
-        MaybeCPType = no
+        unexpected(this_file, string.format(
+            "coverage_prof_second_pass_goal: Coverage information is unknown\n"
+            ++ "\tGoalPath: %s",
+            [s(goal_path_to_string(GoalPath))]))
     ;
-        CoverageAfterGoals = CPOptions ^ cpo_coverage_after_goal,
-        (
-            CoverageAfterGoals  = yes,
-            MaybeCPType = yes(cp_type_coverage_after)
-        ;
-            CoverageAfterGoals = no,
-            MaybeCPType = no
-        )
+        true
     ),
 
-    % Step 2.
-    %
-    % Update coverage known information.
-    (
-        MaybeCPType = yes(_),
-        CoverageAfterKnown2 = coverage_after_known
-    ;
-        MaybeCPType = no,
-        CoverageAfterKnown2 = CoverageAfterKnown1
-    ),
-    % If the goal has a port count, then coverage is known at the point directy
-    % before this goal.
-    (
-        GoalPortCountsCoverageAfter = port_counts_give_coverage_after,
-        CoverageAfterKnown = coverage_after_known
-    ;
-        GoalPortCountsCoverageAfter = no_port_counts_give_coverage_after,
-        (
-            % If there is not exactly one solution then the coverage is
-            % not known.
-            ( Detism = detism_semi
-            ; Detism = detism_multi
-            ; Detism = detism_non
-            ; Detism = detism_cc_non
-            ; Detism = detism_erroneous
-            ; Detism = detism_failure
-            ),
-            CoverageAfterKnown = coverage_after_unknown
-        ;
-            % Otherwise the coverage remains the same.
-            ( Detism = detism_det
-            ; Detism = detism_cc_multi
-            ),
-            CoverageAfterKnown = CoverageAfterKnown2
-        )
-    ),
+    % Currently the first pass is unsupported, we don't make use of the
+    % information it provides.
+    DPInfo = goal_info_get_dp_info(GoalInfo0),
+    DPInfo = dp_goal_info(IsMDProfInst, _MaybeDPCoverageInfo),
 
-    % Step 3.
+    % Step 1.
     %
     % Apply transformation recursively.
     (
@@ -2159,93 +2072,112 @@ coverage_prof_second_pass_goal(Goal0, Go
         ; GoalExpr0 = generic_call(_, _, _, _)
         ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
         ),
+        ( goal_expr_has_call_site(GoalExpr0) ->
+            NextCoverageBeforeKnown0 = coverage_before_known
+        ;
+            coverage_known_after_goal_with_detism(Detism, 
+                CoverageBeforeKnown, NextCoverageBeforeKnown0)
+        ),
         AddedImpurityInner = no,
-        GoalExpr1 = GoalExpr0,
-        NextCoverageAfterKnown = CoverageAfterKnown
+        GoalExpr1 = GoalExpr0
     ;
         GoalExpr0 = conj(ConjType, Goals0),
         coverage_prof_second_pass_conj(ConjType, Goals0, Goals,
-            CoverageAfterKnown, NextCoverageAfterKnown, !Info,
+            CoverageBeforeKnown, NextCoverageBeforeKnown0, !Info,
             AddedImpurityInner),
         GoalExpr1 = conj(ConjType, Goals)
     ;
-        % There may be optimizations that can allow us to avoid inserting
-        % superfluous coverage points, however they are most likely to be
-        % non-trivial.
-
         GoalExpr0 = disj(Goals0),
-        coverage_prof_second_pass_disj(DPInfo, Goals0, Goals, !Info,
-            AddedImpurityInner),
-        (
-            ( Detism = detism_det
-            ; Detism = detism_cc_multi
-            ),
-            NextCoverageAfterKnown = CoverageAfterKnown
-        ;
-            ( Detism = detism_semi
-            ; Detism = detism_multi
-            ; Detism = detism_non
-            ; Detism = detism_cc_non
-            ; Detism = detism_erroneous
-            ; Detism = detism_failure
-            ),
-            NextCoverageAfterKnown = coverage_after_unknown
-        ),
+        coverage_prof_second_pass_disj(DPInfo, 
+            CoverageBeforeKnown, NextCoverageBeforeKnown0,
+            Goals0, Goals, !Info, AddedImpurityInner),
         GoalExpr1 = disj(Goals)
     ;
         GoalExpr0 = switch(Var, SwitchCanFail, Cases0),
         coverage_prof_second_pass_switchcase(DPInfo, SwitchCanFail,
-            Cases0, Cases, CoverageAfterKnown, NextCoverageAfterKnown0, !Info,
-            AddedImpurityInner),
-        (
-            SwitchCanFail = cannot_fail,
-            NextCoverageAfterKnown = NextCoverageAfterKnown0
-        ;
-            SwitchCanFail = can_fail,
-            NextCoverageAfterKnown = coverage_after_unknown
-        ),
+            Cases0, Cases, CoverageBeforeKnown, NextCoverageBeforeKnown0,
+            !Info, AddedImpurityInner),
         GoalExpr1 = switch(Var, SwitchCanFail, Cases)
     ;
         GoalExpr0 = negation(NegGoal0),
-        % The coverage after a negated goal is always unknown.
         coverage_prof_second_pass_goal(NegGoal0, NegGoal, 
-            coverage_after_unknown, NextCoverageAfterKnown, !Info,
+            CoverageBeforeKnown, _, !Info,
             AddedImpurityInner),
+        % The coverage after a negated goal cannot be inferred from it's inner
+        % goals.
+        coverage_known_after_goal_with_detism(Detism, 
+            CoverageBeforeKnown, NextCoverageBeforeKnown0),
         GoalExpr1 = negation(NegGoal)
     ;
         GoalExpr0 = scope(Reason, ScopeGoal0),
+        coverage_prof_second_pass_goal(ScopeGoal0, ScopeGoal,
+            CoverageBeforeKnown, CoverageAfterScopedGoalKnown, !Info,
+            AddedImpurityInner),
         % A scope may cut away solutions, if it does we don't know the number
         % of solutions of the scoped goal.
         ScopedGoalDetism =
             ScopeGoal0 ^ hlds_goal_info ^ goal_info_get_determinism,
         ( ScopedGoalDetism = Detism ->
-            CoverageAfterScopedGoalKnown = CoverageAfterKnown
+            NextCoverageBeforeKnown0 = CoverageAfterScopedGoalKnown
         ;
-            CoverageAfterScopedGoalKnown = coverage_after_unknown
+            coverage_known_after_goal_with_detism(Detism, 
+                CoverageBeforeKnown, NextCoverageBeforeKnown0)
         ),
-        coverage_prof_second_pass_goal(ScopeGoal0, ScopeGoal,
-            CoverageAfterScopedGoalKnown, NextCoverageAfterKnown, !Info,
-            AddedImpurityInner),
         GoalExpr1 = scope(Reason, ScopeGoal)
     ;
         GoalExpr0 = if_then_else(ITEExistVars, Cond, Then, Else),
         coverage_prof_second_pass_ite(DPInfo, ITEExistVars, Cond, Then, Else,
-            GoalExpr1, CoverageAfterKnown, NextCoverageAfterKnown, !Info,
+            GoalExpr1, CoverageBeforeKnown, NextCoverageBeforeKnown0, !Info,
             AddedImpurityInner)
     ;
         GoalExpr0 = shorthand(_),
         unexpected(this_file, "coverage_prof_second_pass_goal: shorthand")
     ),
-    add_impurity_if_needed(AddedImpurityInner, GoalInfo0, GoalInfo1),
-    Goal1 = hlds_goal(GoalExpr1, GoalInfo1),
+
+    % Step 3.
+    %
+    % Consider inserting a coverage point after this goal to measure how many
+    % times it succeeds.
+    (
+        (   
+            % Never insert coverage points on goals that are part of the deep
+            % profiling instrumentation.
+            IsMDProfInst = goal_is_mdprof_inst
+        ;
+            % We already have execution counts for the program point after this
+            % goal; adding a counter would be redundant.
+            NextCoverageBeforeKnown0 = coverage_before_known
+        ;
+            % Never insert coverage points after conjunctions; wait until
+            % the algorithm recurses to inside the conjunction and make a
+            % better decision about the last conjunct. This can reduce the
+            % number of coverage points inserted in some cases.
+            GoalExpr0 = conj(_, _)
+        )
+    ->
+        MaybeCPType = no,
+        NextCoverageBeforeKnown = NextCoverageBeforeKnown0
+    ;
+        CoverageAfterGoals = CPOptions ^ cpo_coverage_after_goal,
+        (
+            CoverageAfterGoals  = yes,
+            MaybeCPType = yes(cp_type_coverage_after),
+            NextCoverageBeforeKnown = coverage_before_known
+        ;
+            CoverageAfterGoals = no,
+            MaybeCPType = no,
+            NextCoverageBeforeKnown = NextCoverageBeforeKnown0
+        )
+    ),
 
     % Step 4.
     %
     % Insert the coverage point if we decided to earlier.
+    add_impurity_if_needed(AddedImpurityInner, GoalInfo0, GoalInfo1),
+    Goal1 = hlds_goal(GoalExpr1, GoalInfo1),
     (
         MaybeCPType = yes(CPType),
-        Path = goal_info_get_goal_path(GoalInfo1),
-        CPInfo = coverage_point_info(Path, CPType),
+        CPInfo = coverage_point_info(GoalPath, CPType),
 
         make_coverage_point(CPInfo, CPGoals, !Info),
         create_conj_from_list([Goal1 | CPGoals], plain_conj, Goal),
@@ -2257,26 +2189,67 @@ coverage_prof_second_pass_goal(Goal0, Go
         AddedImpurity = AddedImpurityInner
     ).
 
-    % Perform the coverage profiling transformation for conjuncts starting
-    % at the tail of the goal list and moving back towards the head.  The
-    % goal list represents the list of goals within a conjunction minus
-    % 'Pos' goals removed from the head.
+    % True if the deep profiler will instrument this call site and the port
+    % counts from it are useful for coverage profiling.
     %
-    % This is done tail first as to take advantage of knowledge of goals after
-    % the current goal within the conjunction.
+:- pred goal_expr_has_call_site(hlds_goal_expr::in) is semidet.
+
+goal_expr_has_call_site(GoalExpr) :-
+    (
+        GoalExpr = plain_call(_, _, _, BuiltinState, _, _),
+        ( BuiltinState = out_of_line_builtin
+        ; BuiltinState = not_builtin
+        )
+    ;
+        GoalExpr = generic_call(GenericCall, _, _, _),
+        ( GenericCall = higher_order(_, _, _, _)
+        ; GenericCall = class_method(_, _, _, _)
+        )
+    ;        
+        % Even though the deep profiler creates a call site when these may
+        % call mercury the coverage propagation code cannot make use of the
+        % port counts, since they measure how often Mercury is re-entered,
+        % not how often this call is made.
+        GoalExpr = call_foreign_proc(_, _, _, _, _, _, _),
+        fail
+    ).
+
+:- pred coverage_known_after_goal_with_detism(determinism::in,
+    coverage_before_known::in, coverage_before_known::out) is det.
+
+coverage_known_after_goal_with_detism(Detism, !CoverageKnown) :-
+    (
+        ( Detism = detism_semi
+        ; Detism = detism_multi
+        ; Detism = detism_non
+        ; Detism = detism_cc_non
+        ; Detism = detism_erroneous
+        ; Detism = detism_failure
+        ),
+        !:CoverageKnown = coverage_before_unknown
+    ;
+        ( Detism = detism_det
+        ; Detism = detism_cc_multi
+        )
+    ).
+
+    % Perform the coverage profiling transformation for conjuncts.  The goal
+    % list represents the list of goals within a conjunction minus 'Pos' goals
+    % removed from the head.
     %
 :- pred coverage_prof_second_pass_conj(conj_type::in,
     list(hlds_goal)::in, list(hlds_goal)::out,
-    coverage_after_known::in, coverage_after_known::out,
+    coverage_before_known::in, coverage_before_known::out,
     proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
 
-coverage_prof_second_pass_conj(_, [], [], !CoverageAfterKnown, !Info, no).
+coverage_prof_second_pass_conj(_, [], [], !CoverageBeforeKnown, !Info, no).
 coverage_prof_second_pass_conj(ConjType, [Goal0 | Goals0], Goals,
-        CoverageAfterKnown0, NextCoverageAfterKnown, !Info, AddedImpurity) :-
-    coverage_prof_second_pass_conj(ConjType, Goals0, Goals1,
-        CoverageAfterKnown0, CoverageAfterKnown, !Info, AddedImpurityTail),
+        CoverageBeforeKnown, NextCoverageBeforeKnown, !Info, AddedImpurity) :-
     coverage_prof_second_pass_goal(Goal0, Goal1,
-        CoverageAfterKnown, NextCoverageAfterKnown, !Info, AddedImpurityHead),
+        CoverageBeforeKnown, CoverageBeforeTailKnown, !Info, AddedImpurityHead),
+
+    % Flatten the conjunction, this is necessary when coverage points are
+    % inserted into conjuncts.
     (
         Goal1 = hlds_goal(conj(plain_conj, ConjGoals), _),
         ConjType = plain_conj
@@ -2285,198 +2258,215 @@ coverage_prof_second_pass_conj(ConjType,
     ;
         Goals = [Goal1 | Goals1]
     ),
+
+    coverage_prof_second_pass_conj(ConjType, Goals0, Goals1,
+        CoverageBeforeTailKnown, NextCoverageBeforeKnown, !Info,
+        AddedImpurityTail),
     bool.or(AddedImpurityHead, AddedImpurityTail, AddedImpurity).
 
     % Perform the coverage profiling transformation over goals within a
     % disjunction.  The list of goals represents the tail of the disjunction
     % currently being transformed.
     %
-    % Disjuncts are also transformed in reverse order, as knowledge from
-    % later disjuncts can be used to reduce the number of coverage points
-    % placed in earlier disjuncts.
-    %
-:- pred coverage_prof_second_pass_disj(
-    dp_goal_info::in, list(hlds_goal)::in, list(hlds_goal)::out,
+:- pred coverage_prof_second_pass_disj(dp_goal_info::in, 
+    coverage_before_known::in, coverage_before_known::out,
+    list(hlds_goal)::in, list(hlds_goal)::out, 
     proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
 
-coverage_prof_second_pass_disj(_, [], [], !Info, no).
-coverage_prof_second_pass_disj(DPInfo, [Goal0 | Goals0], [Goal | Goals], !Info,
-        AddedImpurity) :-
-    % Transform the tail of the disjunction.
-    coverage_prof_second_pass_disj(DPInfo, Goals0, Goals, !Info,
-        AddedImpurityTail),
+coverage_prof_second_pass_disj(DPInfo, CoverageBeforeKnown,
+        NextCoverageBeforeKnown, Disjs0, Disjs, !Info, AddedImpurity) :-
+    % If the disjunction was introduced by the deep profiling pass, it has two
+    % disjuncts and it's second disjunct has 'failure' determinism, then
+    % perform the coverage profiling pass on the first disjunct as if this
+    % is the only goal. 
+    (
+        DPInfo = dp_goal_info(goal_is_mdprof_inst, _),
+        Disjs0 = [FirstDisj0, SecondDisj],
+        SecondDisj ^ hlds_goal_info ^ goal_info_get_determinism = detism_failure
+    ->
+        coverage_prof_second_pass_goal(FirstDisj0, FirstDisj,
+            CoverageBeforeKnown, NextCoverageBeforeKnown, !Info,
+            AddedImpurity),
+        Disjs = [FirstDisj, SecondDisj]
+    ;
+        coverage_prof_second_pass_disj_2(DPInfo, CoverageBeforeKnown, 
+            Disjs0, Disjs, !Info, AddedImpurity),
+        NextCoverageBeforeKnown = coverage_before_unknown
+    ).
 
-    % Transform this goal and optionally add a coverage point before it.
-    coverage_prof_second_pass_goal(Goal0, Goal1,
-        coverage_after_unknown, NextCoverageAfterKnown, !Info,
-        AddedImpurityHead0),
+:- pred coverage_prof_second_pass_disj_2(dp_goal_info::in, 
+    coverage_before_known::in,
+    list(hlds_goal)::in, list(hlds_goal)::out, 
+    proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
+
+coverage_prof_second_pass_disj_2(_, _, [], [], !Info, no).
+coverage_prof_second_pass_disj_2(DPInfo, CoverageBeforeKnown0, 
+        [Goal0 | Goals0], [Goal | Goals], !Info, AddedImpurity) :-
+    % If coverage is unknown before the disjunct, then decide to insert a
+    % branch coverage point at the beginning of the disjunct.
     CPOBranchDisj = !.Info ^ ci_coverage_profiling_opts ^ cpo_branch_disj,
     DPInfo = dp_goal_info(IsMDProfInst, _),
     (
         CPOBranchDisj = yes,
-        NextCoverageAfterKnown = coverage_after_unknown,
+        CoverageBeforeKnown0 = coverage_before_unknown,
         IsMDProfInst = goal_is_not_mdprof_inst
     ->
+        InsertCP = yes,
+        CoverageBeforeKnown = coverage_before_known
+    ;
+        InsertCP = no,
+        CoverageBeforeKnown = CoverageBeforeKnown0
+    ),
+
+    % Transform the disjunct its self.
+    coverage_prof_second_pass_goal(Goal0, Goal1,
+        CoverageBeforeKnown, _CoverageAfterHeadKnown, !Info,
+        AddedImpurityHead),
+
+    % Transform the tail of the disjunction.
+    coverage_prof_second_pass_disj_2(DPInfo,
+        coverage_before_unknown, Goals0, Goals, !Info,
+        AddedImpurityTail),
+
+    % Insert the coverage point if we decided to above.
+    (
+        InsertCP = yes
+    ->
         DisjPath = goal_info_get_goal_path(Goal0 ^ hlds_goal_info),
         insert_coverage_point_before(coverage_point_info(DisjPath,
             cp_type_branch_arm), Goal1, Goal, !Info),
-        AddedImpurityHead = yes
+        AddedImpurity = yes
     ;
         Goal = Goal1,
-        AddedImpurityHead = AddedImpurityHead0
-    ),
-
-    bool.or(AddedImpurityHead, AddedImpurityTail, AddedImpurity).
+        AddedImpurity = bool.or(AddedImpurityHead, AddedImpurityTail)
+    ).
 
+    % coverage_prof_second_pass_switchcase(DPInfo, SwitchCanFial, !Cases,
+    %   CoverageBeforeSwitch, !Info, AddedImpurity).
+    %
+    % Preform coverage profiling transformation on switch cases. 
+    %
 :- pred coverage_prof_second_pass_switchcase(dp_goal_info::in, can_fail::in,
     list(case)::in, list(case)::out,
-    coverage_after_known::in, coverage_after_known::out,
+    coverage_before_known::in, coverage_before_known::out,
+    proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
+
+coverage_prof_second_pass_switchcase(DPInfo, CanFail, Cases0, Cases,
+        CoverageBeforeSwitchKnown, CoverageAfterSwitchKnown, !Info, AddedImpurity) :-
+    % If the switch can fail then the coverage after it will be unknown.
+    (
+        CanFail = can_fail,
+        CoverageAfterSwitchKnown0 = coverage_before_unknown
+    ;
+        CanFail = cannot_fail,
+        CoverageAfterSwitchKnown0 = coverage_before_known
+    ),
+    coverage_prof_second_pass_switchcase_2(DPInfo, CanFail, Cases0, Cases,
+        CoverageBeforeSwitchKnown, coverage_before_known,
+        CoverageAfterSwitchKnown0, CoverageAfterSwitchKnown, !Info,
+        AddedImpurity).
+
+:- pred coverage_prof_second_pass_switchcase_2(dp_goal_info::in, can_fail::in,
+    list(case)::in, list(case)::out, coverage_before_known::in, 
+    coverage_before_known::in, 
+    coverage_before_known::in,  coverage_before_known::out,
     proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
 
-coverage_prof_second_pass_switchcase(_, _, [], [], _, coverage_after_known,
-        !Info, no).
-coverage_prof_second_pass_switchcase(DPInfo, SwitchCanFail,
-        [Case0 | Cases0], [Case | Cases], CoverageAfterSwitchKnown,
-        NextCoverageAfterKnown, !Info, AddedImpurity) :-
+coverage_prof_second_pass_switchcase_2(_, _, [], [], _, _,
+        !CoverageAfterSwitchKnown, !Info, no). 
+
+coverage_prof_second_pass_switchcase_2(DPInfo, SwitchCanFail,
+        [Case0 | Cases0], [Case | Cases], CoverageBeforeSwitchKnown,
+        CoverageBeforeEveryCaseKnown, !CoverageAfterSwitchKnown, !Info,
+        AddedImpurity) :-
     Goal0 = Case0 ^ case_goal,
 
     % If the switch cannot fail and this is the last case then the coverage
-    % at the end of this case can be computed from the coverage after the
-    % entire switch and coverage information for the tail of the switch
-    % such as branch coverage points.
-
+    % at the beginning of this case can be computed from the coverage before the
+    % entire switch and coverage information for the tail of the switch such as
+    % branch coverage points.
     (
         Cases0 = [],
         (
             SwitchCanFail = cannot_fail,
-            CoverageAfterHeadKnown = CoverageAfterSwitchKnown
+            CoverageBeforeHeadKnown0 = coverage_before_known_and(
+                CoverageBeforeSwitchKnown, CoverageBeforeEveryCaseKnown)
         ;
             SwitchCanFail = can_fail,
-            CoverageAfterHeadKnown = coverage_after_unknown
+            CoverageBeforeHeadKnown0 = coverage_before_unknown
         )
     ;
         Cases0 = [_ | _],
-        CoverageAfterHeadKnown = coverage_after_unknown
+        CoverageBeforeHeadKnown0 = coverage_before_unknown
     ),
 
-    coverage_prof_second_pass_goal(Goal0, Goal1, CoverageAfterHeadKnown,
-        NextCoverageAfterKnown0, !Info, AddedImpurityHead0),
-
-    % Possibly insert coverage point.
+    % Decide whether to insert a coverage point here.
     CPOBranchSwitch = !.Info ^ ci_coverage_profiling_opts ^
         cpo_branch_switch,
     DPInfo = dp_goal_info(IsMDProfInst, _),
     (
         CPOBranchSwitch = yes,
-        NextCoverageAfterKnown0 = coverage_after_unknown,
+        CoverageBeforeHeadKnown0 = coverage_before_unknown,
         IsMDProfInst = goal_is_not_mdprof_inst
     ->
+        InsertCP = yes,
+        CoverageBeforeHeadKnown = coverage_before_known
+    ;      
+        InsertCP = no,
+        CoverageBeforeHeadKnown = CoverageBeforeHeadKnown0
+    ),
+        
+    coverage_prof_second_pass_goal(Goal0, Goal1, CoverageBeforeHeadKnown,
+        CoverageAfterCaseKnown, !Info, AddedImpurityHead0),
+    !:CoverageAfterSwitchKnown = coverage_before_known_and(
+        CoverageAfterCaseKnown, !.CoverageAfterSwitchKnown),
+
+    % Possibly insert coverage point.
+    (   
+        InsertCP = yes,
         CasePath = goal_info_get_goal_path(Goal0 ^ hlds_goal_info),
         insert_coverage_point_before(coverage_point_info(CasePath,
             cp_type_branch_arm), Goal1, Goal, !Info),
-        AddedImpurityHead = yes,
-        NextCoverageAfterKnownHead = coverage_after_known
+        AddedImpurityHead = yes
     ;
+        InsertCP = no,
         Goal = Goal1,
-        AddedImpurityHead = AddedImpurityHead0,
-        NextCoverageAfterKnownHead = NextCoverageAfterKnown0
+        AddedImpurityHead = AddedImpurityHead0
     ),
 
     % Handle recursive case and prepare output variables.
-    coverage_prof_second_pass_switchcase(DPInfo, SwitchCanFail, Cases0, Cases,
-        CoverageAfterSwitchKnown, NextCoverageAfterKnownTail, !Info,
-        AddedImpurityTail),
+    NextCoverageBeforeEveryCaseKnown = coverage_before_known_and(
+        CoverageBeforeEveryCaseKnown, CoverageBeforeHeadKnown),
+    coverage_prof_second_pass_switchcase_2(DPInfo, SwitchCanFail, Cases0, Cases,
+        CoverageBeforeSwitchKnown, NextCoverageBeforeEveryCaseKnown, 
+        !CoverageAfterSwitchKnown, !Info, AddedImpurityTail),
     Case = Case0 ^ case_goal := Goal,
-    coverage_after_known_branch(NextCoverageAfterKnownHead,
-        NextCoverageAfterKnownTail, NextCoverageAfterKnown),
     bool.or(AddedImpurityHead, AddedImpurityTail, AddedImpurity).
 
     % Determine if branch coverage points should be inserted in either or
     % both of the then and else branches, insert them and transform the
     % sub-goals.
     %
-    % This is performed by first transforming the Else and Then branches,
-    % then making decisions about cooverage points and inserting them, then
-    % transforming the condition and constructing the new ITE goal_expr.
+    % This is performed by first transforming the condition goal,
+    % then making decisions about coverage points and inserting them, then
+    % transforming the then and else branches and constructing the new ITE
+    % goal_expr.
     %
 :- pred coverage_prof_second_pass_ite(dp_goal_info::in, list(prog_var)::in,
     hlds_goal::in, hlds_goal::in, hlds_goal::in, hlds_goal_expr::out,
-    coverage_after_known::in, coverage_after_known::out,
+    coverage_before_known::in, coverage_before_known::out,
     proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
 
 coverage_prof_second_pass_ite(DPInfo, ITEExistVars, Cond0, Then0, Else0,
-        GoalExpr, CoverageAfterITEKnown, NextCoverageAfterKnown,
+        GoalExpr, CoverageBeforeITEKnown, NextCoverageBeforeKnown,
         !Info, AddedImpurity) :-
-    % If the then and else goals have exactly one solution and coverage is
-    % known after the ite, then the coverage at the end of one branch can
-    % be computed from the other branch and the coverage known after the ite.
-    % This helps later to insert fewer coverage points in the beginning of
-    % the branches, and may also help reduce coverage points within the
-    % branches.
-            
-    ThenPortCountsCoverageAfter = goal_get_maybe_dp_port_counts_coverage(Then0),
-    ElsePortCountsCoverageAfter = goal_get_maybe_dp_port_counts_coverage(Else0),
-    (
-        CoverageAfterITEKnown = coverage_after_known,
-        ThenDetism = Then0 ^ hlds_goal_info ^ goal_info_get_determinism,
-        ElseDetism = Else0 ^ hlds_goal_info ^ goal_info_get_determinism,
-        (
-            ( ThenDetism = detism_det
-            ; ThenDetism = detism_cc_multi
-            ),
-            ( ElseDetism = detism_det
-            ; ElseDetism = detism_cc_multi
-            )
-        ->
-            (
-                ThenPortCountsCoverageAfter = 
-                    no_port_counts_give_coverage_after,
-                ElsePortCountsCoverageAfter = 
-                    no_port_counts_give_coverage_after,
-                
-                % The coverage at the end of the else goal can be calculated
-                % from the coverage at the end of the then goal.
-                CoverageAfterThenKnown = coverage_after_unknown,
-                CoverageAfterElseKnown = coverage_after_known
-            ;
-                ThenPortCountsCoverageAfter = 
-                    no_port_counts_give_coverage_after,
-                ElsePortCountsCoverageAfter = port_counts_give_coverage_after,
-
-                % The coverage at the end of the then goal can be calculated
-                % from the coverage at the end of the else goal.
-                CoverageAfterThenKnown = coverage_after_known,
-                CoverageAfterElseKnown = coverage_after_known
-            ;
-                ThenPortCountsCoverageAfter = port_counts_give_coverage_after,
-
-                % The coverage at the end of the else goal (if it doesn't have
-                % port counts), can be calculated from the coverage of the then
-                % goal.  Or it's already known because the port counts from
-                % within the goal give the coverage information.
-                CoverageAfterThenKnown = coverage_after_known,
-                CoverageAfterElseKnown = coverage_after_known
-            )
-        ;
-            % The branches of the ITE are not deterministic.
-            CoverageAfterThenKnown = coverage_after_unknown,
-            CoverageAfterElseKnown = coverage_after_unknown
-        )        
-    ;
-        CoverageAfterITEKnown = coverage_after_unknown,
-        CoverageAfterElseKnown = coverage_after_unknown,
-        CoverageAfterThenKnown = coverage_after_unknown
-    ),
-
-    % Transform Else branch,
-    coverage_prof_second_pass_goal(Else0, Else1,
-        CoverageAfterElseKnown, CoverageBeforeElseKnown1, !Info,
-        AddedImpurityElseGoal),
+    % Transform Cond branch.
+    coverage_prof_second_pass_goal(Cond0, Cond,
+        CoverageBeforeITEKnown, CoverageKnownAfterCond, !Info,
+        AddedImpurityCond),
 
-    % Transform Then branch.
-    coverage_prof_second_pass_goal(Then0, Then1,
-        CoverageAfterThenKnown, CoverageBeforeThenKnown1, !Info,
-        AddedImpurityThenGoal),
+    CoverageKnownBeforeThen0 = CoverageKnownAfterCond,
+    CoverageKnownBeforeElse0 = coverage_before_unknown,
 
     % Gather information and decide what coverage points to insert.
     %
@@ -2486,59 +2476,69 @@ coverage_prof_second_pass_ite(DPInfo, IT
     %
     % Whatever we do we will ensure that the coverage will be known at the
     % beginning of each branch,
-
     CPOBranchIf = !.Info ^ ci_coverage_profiling_opts ^ cpo_branch_ite,
-    CondPortCountsCoverageAfter = goal_get_maybe_dp_port_counts_coverage(Cond0),
     DPInfo = dp_goal_info(IsMDProfInst, _),
     (
         CPOBranchIf = yes,
-        CondPortCountsCoverageAfter = no_port_counts_give_coverage_after,
         IsMDProfInst = goal_is_not_mdprof_inst
     ->
         (
-            CoverageBeforeThenKnown1 = coverage_after_unknown,
+            CoverageKnownBeforeThen0 = coverage_before_unknown,
             ThenPath = goal_info_get_goal_path(Then0 ^ hlds_goal_info),
             InsertCPThen = yes(coverage_point_info(ThenPath,
                 cp_type_branch_arm))
         ;
-            CoverageBeforeThenKnown1 = coverage_after_known,
-            InsertCPThen = no
-        )
-    ;
-        % Don't insert any coverage points,
+            CoverageKnownBeforeThen0 = coverage_before_known,
         InsertCPThen = no
     ),
-    (
-        CoverageBeforeElseKnown1 = coverage_after_unknown,
+        % Always insert a coverage point for the else branch.
         ElsePath = goal_info_get_goal_path(Else0 ^ hlds_goal_info),
         InsertCPElse = yes(coverage_point_info(ElsePath,
-            cp_type_branch_arm))
+            cp_type_branch_arm)),
+        CoverageKnownBeforeThen = coverage_before_known,
+        CoverageKnownBeforeElse = coverage_before_known
     ;
-        CoverageBeforeElseKnown1 = coverage_after_known,
-        InsertCPElse = no
+        % Don't insert any coverage points,
+        InsertCPThen = no,
+        InsertCPElse = no,
+        CoverageKnownBeforeThen = CoverageKnownBeforeThen0,
+        CoverageKnownBeforeElse = CoverageKnownBeforeElse0
     ),
 
-    % Insert any coverage points.
-    maybe_insert_coverage_point_before(InsertCPElse, Else1, Else,
-        CoverageBeforeElseKnown1, _CoverageBeforeElseKnown, !Info,
-        AddedImpurityElseCP),
-    bool.or(AddedImpurityElseGoal, AddedImpurityElseCP, AddedImpurityElse),
-
-    maybe_insert_coverage_point_before(InsertCPThen, Then1, Then,
-        CoverageBeforeThenKnown1, CoverageBeforeThenKnown, !Info,
-        AddedImpurityThenCP),
-    bool.or(AddedImpurityThenGoal, AddedImpurityThenCP, AddedImpurityThen),
+    % Transform Then and Else branches,
+    coverage_prof_second_pass_goal(Then0, Then1,
+        CoverageKnownBeforeThen, NextCoverageKnownThen, !Info,
+        AddedImpurityThenGoal),
+    coverage_prof_second_pass_goal(Else0, Else1,
+        CoverageKnownBeforeElse, NextCoverageKnownElse, !Info,
+        AddedImpurityElseGoal),
 
-    % Transform Cond branch.
-    CoverageKnownAfterCond = CoverageBeforeThenKnown,
-    coverage_prof_second_pass_goal(Cond0, Cond,
-        CoverageKnownAfterCond, NextCoverageAfterKnown, !Info,
-        AddedImpurityCond),
+    % Insert any coverage points.
+    (
+        InsertCPThen = yes(CPInfoThen),
+        insert_coverage_point_before(CPInfoThen, Then1, Then, !Info),
+        AddedImpurityThen = yes
+    ;
+        InsertCPThen = no,
+        Then = Then1,
+        AddedImpurityThen = AddedImpurityThenGoal
+    ),
+    (
+        InsertCPElse = yes(CPInfoElse),
+        insert_coverage_point_before(CPInfoElse, Else1, Else, !Info),
+        AddedImpurityElse = yes
+    ;
+        InsertCPElse = no,
+        Else = Else1,
+        AddedImpurityElse = AddedImpurityElseGoal
+    ),
 
     % Build goal experession and tidy up.
     AddedImpurity = bool.or(AddedImpurityCond,
         bool.or(AddedImpurityThen, AddedImpurityElse)),
-    GoalExpr = if_then_else(ITEExistVars, Cond, Then, Else).
+    GoalExpr = if_then_else(ITEExistVars, Cond, Then, Else),
+    NextCoverageBeforeKnown = coverage_before_known_and(
+        NextCoverageKnownThen, NextCoverageKnownElse).
 
 :- func goal_info_get_dp_info(hlds_goal_info) = dp_goal_info.
 
@@ -2600,12 +2600,12 @@ goal_info_set_mdprof_inst(IsMDProfInst, 
     %
 :- pred maybe_insert_coverage_point_before(maybe(coverage_point_info)::in,
     hlds_goal::in, hlds_goal::out,
-    coverage_after_known::in, coverage_after_known::out,
+    coverage_before_known::in, coverage_before_known::out,
     proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
 
-maybe_insert_coverage_point_before(no, !Goal, !CoverageAfterKnown, !Info, no).
+maybe_insert_coverage_point_before(no, !Goal, !CoverageBeforeKnown, !Info, no).
 maybe_insert_coverage_point_before(yes(CPInfo), !Goal,
-        _, coverage_after_known, !Info, yes) :-
+        _, coverage_before_known, !Info, yes) :-
     insert_coverage_point_before(CPInfo, !Goal, !Info).
 
     % Insert a coverage point before the given goal. This returns a flat
@@ -2627,30 +2627,20 @@ insert_coverage_point_before(CPInfo, !Go
     % Used to describe if coverage information is known at a partiular point
     % within a procedure.
     %
-:- type coverage_after_known
-    --->    coverage_after_known
-    ;       coverage_after_unknown.
-
-    % Merge two coverage_after_known values at the beginning of a branch.
-    %
-    % The coverage profiling algorithm moves right to left through conjunctions
-    % and disjunctions, and from inner goals to outer goals on all non-atomic
-    % goals.  It may reach a branch of execution knowing the coverage known
-    % information entering both branches, this predicate computes the coverage
-    % known information for the branch as a whole.  For example.  In an
-    % if-then-else this can compute weather the coverage is known after the
-    % condition based in weather the coverage is known before both the then and
-    % else branches.
-    %
-:- pred coverage_after_known_branch(coverage_after_known::in,
-    coverage_after_known::in, coverage_after_known::out) is det.
-
-coverage_after_known_branch(coverage_after_known, coverage_after_known,
-    coverage_after_known).
-coverage_after_known_branch(coverage_after_known, coverage_after_unknown,
-    coverage_after_unknown).
-coverage_after_known_branch(coverage_after_unknown, _,
-    coverage_after_unknown).
+:- type coverage_before_known
+    --->    coverage_before_known
+    ;       coverage_before_unknown.
+
+    % The logical 'and' of coverage_before_known values.
+:- func coverage_before_known_and(coverage_before_known, coverage_before_known)
+    = coverage_before_known.
+
+coverage_before_known_and(coverage_before_known, coverage_before_known) =
+    coverage_before_known.
+coverage_before_known_and(coverage_before_known, coverage_before_unknown) =
+    coverage_before_unknown.
+coverage_before_known_and(coverage_before_unknown, _) =
+    coverage_before_unknown.
 
     % Create a coverage info struture, initializing some values to sensible
     % defaults.
@@ -2722,7 +2712,7 @@ has_port_counts_after(Goal, PCDirect, PC
         has_port_counts_if_det(Detism, PCBefore, PC)
     ).
 
-    % Given the current goal's determinism and wheather the next earliest goal
+    % Given the current goal's determinism and whether the next earliest goal
     % has port counts does this goal have port counts
     %
 :- pred has_port_counts_if_det(determinism::in,
@@ -2745,10 +2735,13 @@ has_port_counts_if_det(Detism, PortCount
     % transformation.
     %
     % This pass gathers the information in the dp_coverage_goal_info structure,
-    % namely weather the goal is trivial (if it and none of it's subgoals are
-    % calls),  And weather a port count is available from the deep profiler
+    % namely whether the goal is trivial (if it and none of it's subgoals are
+    % calls),  And whether a port count is available from the deep profiler
     % from which the coverage _after_ this goal can be computed.
     %
+    % XXX: Currently the first pass is unsupported. The second pass does not
+    % use the information it generates.
+    %
 :- pred coverage_prof_first_pass(coverage_profiling_options::in, hlds_goal::in,
     hlds_goal::out, port_counts_give_coverage_after::in,
     dp_coverage_goal_info::out) is det.
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.478
diff -u -p -b -r1.478 mercury_compile.m
--- compiler/mercury_compile.m	5 Sep 2008 03:57:36 -0000	1.478
+++ compiler/mercury_compile.m	24 Sep 2008 04:33:39 -0000
@@ -4409,7 +4409,7 @@ maybe_deep_profiling(Verbose, Stats, !HL
         maybe_write_string(Verbose,
             "% Applying deep profiling transformation...\n", !IO),
         maybe_flush_output(Verbose, !IO),
-        apply_deep_profiling_transformation(!HLDS),
+        apply_deep_profiling_transformation(!HLDS, !IO),
         maybe_write_string(Verbose, "% done.\n", !IO),
         maybe_report_stats(Stats, !IO)
     ;
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.631
diff -u -p -b -r1.631 options.m
--- compiler/options.m	24 Sep 2008 06:47:14 -0000	1.631
+++ compiler/options.m	25 Sep 2008 12:52:58 -0000
@@ -304,6 +304,7 @@
     ;       profile_deep_coverage_branch_disj
 
             % Tunables for the coverage profiling pass.
+            % XXX: Currently both these options are unsupported.
     ;       profile_deep_coverage_use_portcounts
     ;       profile_deep_coverage_use_trivial
 
@@ -1167,8 +1168,8 @@ option_defaults_2(compilation_model_opti
     profile_deep_coverage_branch_ite    -   bool(yes),
     profile_deep_coverage_branch_switch -   bool(yes),
     profile_deep_coverage_branch_disj   -   bool(yes),
-    profile_deep_coverage_use_portcounts -  bool(yes),
-    profile_deep_coverage_use_trivial   -   bool(yes),
+    profile_deep_coverage_use_portcounts -  bool(no),
+    profile_deep_coverage_use_trivial   -   bool(no),
     profile_for_implicit_parallelism    -   bool(no),
     use_zeroing_for_ho_cycles           -   bool(yes),
     use_lots_of_ho_specialization       -   bool(no),
Index: deep_profiler/program_representation_utils.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/program_representation_utils.m,v
retrieving revision 1.4
diff -u -p -b -r1.4 program_representation_utils.m
--- deep_profiler/program_representation_utils.m	21 Sep 2008 12:05:06 -0000	1.4
+++ deep_profiler/program_representation_utils.m	25 Sep 2008 12:56:13 -0000
@@ -185,10 +185,10 @@ print_goal_to_strings(VarTable, Indent, 
         GoalExprRep = scope_rep(SubGoalRep, MaybeCut),
         (
             MaybeCut = scope_is_cut,
-            CutString = cord.empty 
+            CutString = cord.singleton(" cut")
         ;
             MaybeCut = scope_is_no_cut,
-            CutString = cord.singleton(" cut")
+            CutString = cord.empty 
         ),
         print_goal_to_strings(VarTable, Indent + 1, SubGoalRep, SubGoalString),
         Strings = indent(Indent) ++ DetismString ++ GoalAnnotationString ++ 
@@ -507,6 +507,19 @@ modulerep_search_proc(ModuleRep, ProcLab
 
 %----------------------------------------------------------------------------%
 
+    % Annotate a procedure representation structure with coverage information.
+    %
+    % The following trace flags control debugging for this predicate.
+    %   
+    %   debug_coverage_propagation:
+    %       Print out diagnostic messages to aid in the debugging of the
+    %       propagation coverage algorithm.
+    %   
+    %   no_coverage_propagation_assertions:
+    %       Disable assertions used to test this algorithm, This allows the
+    %       algorithm to proceed past the problem and allow the programmer to
+    %       view erroneous output.
+    %
 procrep_annotate_with_coverage(OwnProf, CallSites, SolnsCoveragePoints,
         BranchCoveragePoints, !ProcRep) :-
     some [!ProcDefn, !GoalRep] (
@@ -542,6 +555,81 @@ procrep_annotate_with_coverage(OwnProf, 
                 cri_branch_coverage_points  :: map(goal_path, coverage_point)
             ).
 
+    % Try to get coverage information from:
+    %   + Port counts if this is an atomic goal.
+    %   + A solution count from a coverage point after the goal
+    %   + If the goal is in a conjunction and it is not the first conjunct, try
+    %     to get the solution count of the previous goal.
+    %
+    % This does not check for branch entry counts.
+    %
+:- pred get_coverage_information(coverage_reference_info::in,
+    goal_expr_rep(T)::in, goal_path::in, detism_rep::in,
+    coverage_info::in, coverage_info::out) is det.
+
+get_coverage_information(Info, GoalExpr, GoalPath, Detism, !Coverage) :-
+    % Try to get coverage information from goal port counts.
+    (
+        ( !.Coverage = coverage_unknown
+        ; !.Coverage = coverage_known_before(_)
+        ; !.Coverage = coverage_known_after(_)
+        ),
+        GoalExpr = atomic_goal_rep(_, _, _, AtomicGoal),
+        ( AtomicGoal = higher_order_call_rep(_, _)
+        ; AtomicGoal = method_call_rep(_, _, _)
+        ; AtomicGoal = plain_call_rep(_, _, _)
+        ; AtomicGoal = builtin_call_rep(_, _, _)
+        ; AtomicGoal = pragma_foreign_code_rep(_)
+        )
+    ->
+        ( 
+            map.search(Info ^ cri_call_sites, GoalPath, CallSite), 
+            % Callback call sites measure the port counts when mercury is
+            % re-entered, not the number of calls made from this call site.
+            CallSite ^ csf_kind \= callback_and_no_info
+        ->
+            Summary = CallSite ^ csf_summary_perf,
+            % Entry due to redo is not counted at the point before the
+            % goal, it's represented when the number of exists is greater
+            % than the number of calls,  This won't work with nondet code
+            % which should be fixed in the future.
+            Calls = Summary ^ perf_row_calls,
+            Exits = Summary ^ perf_row_exits, 
+            !:Coverage = coverage_known(Calls, Exits)
+        ;
+            (
+                % These goal call types must have call sites, whereas some
+                % builtins and foreign code pragmas may not.
+                ( AtomicGoal = higher_order_call_rep(_, _)
+                ; AtomicGoal = method_call_rep(_, _, _)
+                ; AtomicGoal = plain_call_rep(_, _, _)
+                )
+            ->
+                error("Couldn't look up call site for port counts GP: " ++
+                    goal_path_to_string(GoalPath))
+            ;
+                true
+            )
+        )
+    ;
+        true
+    ),
+
+    % Search for a coverage point after this goal.
+    (
+        ( !.Coverage = coverage_unknown
+        ; !.Coverage = coverage_known_before(_)
+        ),
+        map.search(Info ^ cri_solns_coverage_points, GoalPath, CoveragePoint1)
+    ->
+        CoveragePoint1 = coverage_point(Count1, _, _),
+        !:Coverage = merge_coverage(!.Coverage, coverage_known_after(Count1))
+    ;
+        true
+    ),
+
+    propagate_coverage(Detism, GoalPath, !Coverage).
+
     % Annotate a goal and it's children with coverage information.
     %
 :- pred goal_annotate_coverage(coverage_reference_info::in, goal_path::in,
@@ -552,26 +640,12 @@ goal_annotate_coverage(Info, GoalPath, !
     Goal0 = goal_rep(GoalExpr0, Detism, _),
 
     % Gather any coverage information about this goal and apply it.
-    (
-        get_coverage_after(!.Coverage) = coverage_unknown,
-        map.search(Info ^ cri_solns_coverage_points, GoalPath, CoveragePoint)
-    ->
-        CoveragePoint = coverage_point(Coverage, _, _),
-        !:Coverage = merge_coverage(get_coverage_before(!.Coverage),
-            coverage_known_after(Coverage))
-    ;
-        true
-    ),
-    % TODO: Infer that if a goal has a coverage of exactly 0 before it, then it
-    % must have a coverage of exactly 0 after it.  And that a goal that cannot
-    % fail that has a coverage of 0 after it, must have a coverage of 0 before
-    % it.
-    maybe_propagate_det_coverage(Detism, GoalPath, !Coverage),
+    get_coverage_information(Info, GoalExpr0, GoalPath, Detism, !Coverage),
 
     % Calculate coverage of any inner goals.
     (
         GoalExpr0 = conj_rep(Conjuncts0),
-        conj_annotate_coverage(Info, GoalPath, 1, !Coverage,
+        conj_annotate_coverage(Info, GoalPath, !Coverage,
             Conjuncts0, Conjuncts),
         GoalExpr = conj_rep(Conjuncts)
     ;
@@ -581,7 +655,7 @@ goal_annotate_coverage(Info, GoalPath, !
         GoalExpr = disj_rep(Disjuncts)
     ;
         GoalExpr0 = switch_rep(Var, CanFail, Cases0),
-        switch_annotate_coverage(Info, Detism, GoalPath, !Coverage,
+        switch_annotate_coverage(Info, CanFail, GoalPath, !Coverage,
             Cases0, Cases),
         GoalExpr = switch_rep(Var, CanFail, Cases)
     ;
@@ -601,51 +675,9 @@ goal_annotate_coverage(Info, GoalPath, !
         GoalExpr = scope_rep(ScopedGoal, MaybeCut)
     ;
         GoalExpr0 = atomic_goal_rep(Filename, Line, Vars, AtomicGoal),
-        ( 
-            ( AtomicGoal = unify_construct_rep(_, _, _)
-            ; AtomicGoal = unify_deconstruct_rep(_, _, _)
-            ; AtomicGoal = partial_deconstruct_rep(_, _, _)
-            ; AtomicGoal = partial_construct_rep(_, _, _)
-            ; AtomicGoal = unify_assign_rep(_, _)
-            ; AtomicGoal = cast_rep(_, _)
-            ; AtomicGoal = unify_simple_test_rep(_, _)
-            ; AtomicGoal = event_call_rep(_, _)
-            )
-        ;
-            ( AtomicGoal = higher_order_call_rep(_, _)
-            ; AtomicGoal = method_call_rep(_, _, _)
-            ; AtomicGoal = plain_call_rep(_, _, _)
-            ; AtomicGoal = builtin_call_rep(_, _, _)
-            ; AtomicGoal = pragma_foreign_code_rep(_)
-            ),
-            ( map.search(Info ^ cri_call_sites, GoalPath, CallSite) ->
-                Summary = CallSite ^ csf_summary_perf,
-                % Entry due to redo is not counted at the point before the
-                % goal, it's represented when the number of exists is greater
-                % than the number of calls,  This won't work with nondet code
-                % which should be fixed in the future.
-                Calls = Summary ^ perf_row_calls,
-                Exits = Summary ^ perf_row_exits, 
-                !:Coverage = coverage_known(Calls, Exits)
-            ;
-                (
-                    % These goal call types must have call sites, whereas some
-                    % builtins and foreign code pragmas may not.
-                    ( AtomicGoal = higher_order_call_rep(_, _)
-                    ; AtomicGoal = method_call_rep(_, _, _)
-                    ; AtomicGoal = plain_call_rep(_, _, _)
-                    )
-                ->
-                    error("Couldn't look up call site for port counts GP: " ++
-                        goal_path_to_string(GoalPath))
-                ;
-                    true
-                )
-            )
-        ),
         GoalExpr = atomic_goal_rep(Filename, Line, Vars, AtomicGoal)
     ),
-    maybe_propagate_det_coverage(Detism, GoalPath, !Coverage),
+    propagate_coverage(Detism, GoalPath, !Coverage),
     Goal = goal_rep(GoalExpr, Detism, !.Coverage),
     trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
         io.write_string("goal_annotate_coverage: done\n", !IO),
@@ -654,57 +686,56 @@ goal_annotate_coverage(Info, GoalPath, !
              s(string(Detism)), 
              s(string(!.Coverage))], !IO)
     ),
+    trace [ compile_time(not flag("no_coverage_propagation_assertions")) ]
+    (
+        require(check_coverage_complete(!.Coverage, GoalExpr),
+            string.format("check_coverage_complete failed\n" ++ 
+                "\tCoverage: %s\n\tGoalPath: %s\n",
+                [s(string(!.Coverage)), s(goal_path_to_string(GoalPath))])),
     require(check_coverage_regarding_detism(!.Coverage, Detism), 
         string.format("check_coverage_regarding_detism failed: %s %s", 
-            [s(string(!.Coverage)), s(string(Detism))])).
+                [s(string(!.Coverage)), s(string(Detism))]))
+    ).
+
+    % Annotate a conjunction with coverage information.
+    %
+:- pred conj_annotate_coverage(coverage_reference_info::in, goal_path::in,
+    coverage_info::in, coverage_info::out,
+    list(goal_rep(unit))::in, list(goal_rep(coverage_info))::out) is det.
 
-    % Annotate a conjunction with coverage information.  This folds from the
-    % right over the list of conjuncts (backwards).
+conj_annotate_coverage(Info, GoalPath, !Coverage, Conjs0, Conjs) :-
+    conj_annotate_coverage_2(Info, GoalPath, 1, !Coverage, 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 where the entire
-    % conjunction.  However each goal has it's own coverage.
+    % conjunction.  Each goal also has it's own coverage.
     %
-:- pred conj_annotate_coverage(coverage_reference_info::in, goal_path::in,
+:- pred conj_annotate_coverage_2(coverage_reference_info::in, goal_path::in,
     int::in, coverage_info::in, coverage_info::out,
     list(goal_rep(unit))::in, list(goal_rep(coverage_info))::out) is det.
 
-conj_annotate_coverage(_, GoalPath, ConjunctNum, !Coverage, [], []) :-
+conj_annotate_coverage_2(_, GoalPath, ConjunctNum, !Coverage, [], []) :-
     % The empty conjunction is equivalent to 'true' which is deterministic,
     ConjGoalPath = goal_path_add_at_end(GoalPath, step_conj(ConjunctNum)),
     propagate_det_coverage(ConjGoalPath, !Coverage).
 
-conj_annotate_coverage(Info, GoalPath, ConjunctNum, !Coverage, 
+conj_annotate_coverage_2(Info, GoalPath, ConjunctNum, !Coverage, 
         [Conj0 | Conjs0], [Conj | Conjs]) :-
     split_coverage(!.Coverage, CoverageBefore0, CoverageAfter0),
-    conj_annotate_coverage(Info, GoalPath, ConjunctNum+1,
-        CoverageAfter0, TailCoverage1, Conjs0, Conjs1),
-    split_coverage(TailCoverage1, CoverageBeforeTail1, CoverageAfter1),
 
-    goal_transition_coverage(CoverageAfterHead0, CoverageBeforeTail1),
-    HeadCoverage0 = merge_coverage(CoverageBefore0, CoverageAfterHead0),
     goal_annotate_coverage(Info,
         goal_path_add_at_end(GoalPath, step_conj(ConjunctNum)),
-        HeadCoverage0, HeadCoverage, Conj0, Conj),
-    
-    % If computing the coverage for the head gave us information that can be
-    % used to re-compute the coverage for the tail, and we don't already know
-    % the coverage at the beginning of the tail.  Then re-compute the coverage
-    % for the tail.
+        CoverageBefore0, HeadCoverage, Conj0, Conj),
     split_coverage(HeadCoverage, CoverageBefore, CoverageAfterHead),
-    (
-        CoverageBeforeTail1 = coverage_unknown,
-        CoverageAfterHead = coverage_known_after(Count)
-    -> 
-        CoverageBeforeTail = coverage_known_before(Count),
-        TailCoverage2 = merge_coverage(CoverageBeforeTail, CoverageAfter1),
-        conj_annotate_coverage(Info, GoalPath, ConjunctNum+1,
-            TailCoverage2, TailCoverage, Conjs0, Conjs),
-        CoverageAfter = get_coverage_after(TailCoverage)
-    ;
-        Conjs = Conjs1,
-        CoverageAfter = CoverageAfter1
-    ),
+    goal_transition_coverage(CoverageAfterHead, CoverageBeforeTail),
+    
+    TailCoverage0 = merge_coverage(CoverageBeforeTail, CoverageAfter0), 
+    conj_annotate_coverage_2(Info, GoalPath, ConjunctNum+1, 
+        TailCoverage0, TailCoverage, Conjs0, Conjs),
+    CoverageAfter = get_coverage_after(TailCoverage),
+
     !:Coverage = merge_coverage(CoverageBefore, CoverageAfter).
 
     % Compute the coverage information for a disjunction.
@@ -713,72 +744,50 @@ conj_annotate_coverage(Info, GoalPath, C
     %   - The coverage before a disjunction is equal to the coverage before the
     %     first disjunct.
     %   - The coverage after a disjunction is equal to the sum of coverages
-    %     after each disjunct.
-    %   - If the disjunction has at most one solution, then the coverage
-    %     entering a disjunct is the failure count of the previous disjunct.
-    %
-    % Examples:
-    %   A semidet disjunction.
-    %     5 ( 5 D1 2; 3 D2 2; 1 D3 0 ) 4
-    %
-    %   A nondet disjunction.
-    %     5 ( 5 D1 2; 5 D2 3; 5 D3 1 ) 6 (2 exit, 4 redo)
-    %
-    % For simplicity start with a backwards-only traversal, Not all the rules
-    % described in this comment are applied.
+    %     after each disjunct.  This rule is not yet implemented.
     %
 :- pred disj_annotate_coverage(coverage_reference_info::in, detism_rep::in,
     goal_path::in, coverage_info::in, coverage_info::out,
     list(goal_rep(unit))::in, list(goal_rep(coverage_info))::out) is det.
 
-disj_annotate_coverage(Info, _Detism, GoalPath, !Coverage, 
+disj_annotate_coverage(Info, Detism, GoalPath, !Coverage, 
         Disjs0, Disjs) :-
     CoverageBefore0 = get_coverage_before(!.Coverage),
-    disj_annotate_coverage_2(Info, GoalPath, 1,
-        Disjs0, Disjs, CoverageBefore),
+    Solutions = detism_get_solutions(Detism),
+    disj_annotate_coverage_2(Info, GoalPath, 1, Solutions,
+        CoverageBefore0, Disjs0, Disjs).
 
-    % If coverage before the disjunction was unknown before and is now
-    % discovered, update it.
+:- pred disj_annotate_coverage_2(coverage_reference_info::in,
+    goal_path::in, int::in, solution_count::in,
+    coverage_info::in(coverage_before),
+    list(goal_rep)::in, list(goal_rep(coverage_info))::out) is det.
+
+disj_annotate_coverage_2(_, _, _, _, _, [], []).
+
+disj_annotate_coverage_2(Info, GoalPath, DisjNum, Solutions, CoverageBefore0,
+        [Disj0 | Disjs0], [Disj | Disjs]) :-
+    DisjGoalPath = goal_path_add_at_end(GoalPath, step_disj(DisjNum)),
     (
         CoverageBefore0 = coverage_unknown,
-        CoverageBefore = coverage_known_before(_)
-    ->
-        CoverageAfter = get_coverage_after(!.Coverage),
-        !:Coverage = merge_coverage(CoverageBefore, CoverageAfter)
+        get_branch_coverage(Info, DisjGoalPath, CoverageBefore1)
     ;
-        true
-    ).
-
-:- pred disj_annotate_coverage_2(coverage_reference_info::in,
-    goal_path::in, int::in,
-    list(goal_rep)::in, list(goal_rep(coverage_info))::out,
-    coverage_info::out(coverage_before)) is det.
-
-disj_annotate_coverage_2(_, _, _, [], [], coverage_known_before(0)).
-
-disj_annotate_coverage_2(Info, GoalPath, DisjNum, 
-        [Disj0 | Disjs0], [Disj | Disjs], CoverageBefore) :-
-    disj_annotate_coverage_2(Info, GoalPath, DisjNum + 1,
-        Disjs0, Disjs, _),
-
-    ThisGoalPath = goal_path_add_at_end(GoalPath, step_disj(DisjNum)),
-    get_branch_coverage(Info, ThisGoalPath, CoverageBeforeDisj),
-    % This can be set from the coverage entering the next disjunct, however the
-    % transformation in the compiler doesn't do this, so for simplicity, this
-    % is pessimistic.  Otherwise set is using CoverageBeforeTail.
-    CoverageAfterDisj = coverage_unknown,
-    CoverageDisj0 = merge_coverage(CoverageBeforeDisj, CoverageAfterDisj),
-
-    goal_annotate_coverage(Info, ThisGoalPath, CoverageDisj0, CoverageDisj,
+        CoverageBefore0 = coverage_known_before(_),
+        CoverageBefore1 = CoverageBefore0
+    ),
+    goal_annotate_coverage(Info, DisjGoalPath, CoverageBefore1, _CoverageDisj,
         Disj0, Disj),
-    CoverageBefore = get_coverage_before(CoverageDisj).
 
-:- pred switch_annotate_coverage(coverage_reference_info::in, detism_rep::in,
-    goal_path::in, coverage_info::in, coverage_info::out, 
+    disj_annotate_coverage_2(Info, GoalPath, DisjNum + 1, Solutions, 
+        coverage_unknown, Disjs0, Disjs).
+
+:- pred switch_annotate_coverage(coverage_reference_info::in, 
+    switch_can_fail_rep::in, goal_path::in, 
+    coverage_info::in, coverage_info::out, 
     list(case_rep(unit))::in, list(case_rep(coverage_info))::out) is det.
 
-switch_annotate_coverage(Info, Detism, GoalPath, !Coverage, Cases0, Cases) :-
-    switch_annotate_coverage_2(Info, Detism, GoalPath, 1,
+switch_annotate_coverage(Info, CanFail, GoalPath, !Coverage, Cases0, Cases) :-
+    Coverage0 = !.Coverage,
+    switch_annotate_coverage_2(Info, CanFail, GoalPath, 1,
         coverage_known_det(0), SwitchCoverage, !.Coverage, Cases0, Cases),
     % Use the newly computed coverage if it's more informed than the current
     % coverage.
@@ -809,10 +818,13 @@ switch_annotate_coverage(Info, Detism, G
         !:Coverage = SwitchCoverage
     ),
 
-    require(check_switch_coverage(Detism, Cases, !.Coverage),
+    trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ]
+        io.format("Switch: Coverage0: %s\n", [s(string(Coverage0))], !IO),
+    trace [ compile_time(not flag("no_coverage_propagation_assertions")) ]
+        require(check_switch_coverage(CanFail, Cases, !.Coverage),
         string.format("check_switch_coverage failed\n\t" ++ 
-            "Detism: %s\n\tCases: %s\n\tCoverage: %s\n",
-        [s(string(Detism)), s(string(Cases)), s(string(!.Coverage))])).
+                "CanFail: %s\n\tCases: %s\n\tCoverage: %s\n",
+            [s(string(CanFail)), s(string(Cases)), s(string(!.Coverage))])).
 
     % switch_annotate_coverage_2(Info, Detism, GoalPath, CaseNum, 
     %   !CoverageSum, SwitchCoverage, !Cases),
@@ -827,14 +839,14 @@ switch_annotate_coverage(Info, Detism, G
     % 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, detism_rep::in, 
-    goal_path::in, int::in, coverage_info::in, coverage_info::out,
-    coverage_info::in, 
+:- pred switch_annotate_coverage_2(coverage_reference_info::in, 
+    switch_can_fail_rep::in, goal_path::in, int::in, coverage_info::in,
+    coverage_info::out, coverage_info::in, 
     list(case_rep(unit))::in, list(case_rep(coverage_info))::out) is det.
 
 switch_annotate_coverage_2(_, _, _, _, !CoverageSum, _, [], []).
 
-switch_annotate_coverage_2(Info, Detism, GoalPath, CaseNum, 
+switch_annotate_coverage_2(Info, CanFail, GoalPath, CaseNum, 
         !CoverageSum, SwitchCoverage, [ Case0 | Cases0 ], [ Case | Cases ]) :-
     CaseGoalPath = goal_path_add_at_end(GoalPath, 
         step_switch(CaseNum, no)),
@@ -849,7 +861,7 @@ switch_annotate_coverage_2(Info, Detism,
     %
     (
         Cases0 = [],
-        detism_get_can_fail(Detism) = cannot_fail
+        CanFail = switch_can_not_fail
     ->
         (
             coverage_count_before(SwitchCoverage, SwitchCountBefore),
@@ -885,7 +897,8 @@ switch_annotate_coverage_2(Info, Detism,
     % Keep a sum of the coverage seen in cases so far.
     (
         coverage_count_before(!.CoverageSum, SumCountBefore1),
-        coverage_count_before(Coverage, CountBefore)
+        coverage_count_before(Coverage, CountBefore),
+        CanFail = switch_can_not_fail
     ->
         CoverageSumBefore = coverage_known_before(SumCountBefore1 + CountBefore)
     ;
@@ -901,25 +914,24 @@ switch_annotate_coverage_2(Info, Detism,
     ),
     !:CoverageSum = merge_coverage(CoverageSumBefore, CoverageSumAfter),
 
-    switch_annotate_coverage_2(Info, Detism, GoalPath, CaseNum + 1,
+    switch_annotate_coverage_2(Info, CanFail, GoalPath, CaseNum + 1,
         !CoverageSum, SwitchCoverage, Cases0, Cases).
 
     % Propagate coverage information for if-then-else goals.
     %
     % Step 1:
-    %   Compute the coverage of the Then and Else goals,
+    %   Call goal_annotate_coverage for the condition goal.
     %
     % Step 2:
-    %   Infer and compute coverage information for the cond goal.
+    %   Lookup coverage information for the then and else goals if it cannot be
+    %   inferred from the condition goal.  Set the coverage before the then and
+    %   else goals.
     %   
     % Step 3:
-    %   Infer coverage information for goals using the determinisms of the then
-    %   and else branches and the switch as a whole, and any coverage
-    %   information as computed above.
+    %   Call goal_annotate_coverage for the then and else goals.
     %
     % Step 4:
-    %   Re-compute coverages for any sub goals within the Then and Else goals
-    %   whose coverage is more known than after step 1.
+    %   Calculate the coverage at the end of the entire switch.
     %
 :- pred ite_annotate_coverage(coverage_reference_info::in, goal_path::in,
     coverage_info::in, coverage_info::out, 
@@ -933,147 +945,80 @@ ite_annotate_coverage(Info, GoalPath, !C
     ThenGoalPath = goal_path_add_at_end(GoalPath, step_ite_then),
     ElseGoalPath = goal_path_add_at_end(GoalPath, step_ite_else),
     CondDetism = Cond0 ^ goal_detism_rep,
+    split_coverage(!.Coverage, CoverageBefore0, CoverageAfter0),
 
-    % Step 1, compute coverage of each goal without inference.
-    get_branch_coverage(Info, ThenGoalPath, ThenCoverage0),
-    goal_annotate_coverage(Info, ThenGoalPath, ThenCoverage0, ThenCoverage1,
-        Then0, Then1),
-    get_branch_coverage(Info, ElseGoalPath, ElseCoverage0),
-    goal_annotate_coverage(Info, ElseGoalPath, ElseCoverage0, ElseCoverage1,
-        Else0, Else1),
-    
-    % Step 2: Infer coverage for the Cond goal..
-    ( 
-        get_coverage_before(ThenCoverage1) =
-            coverage_known_before(ThenEntryCount)
-    ->
-        CondCoverageAfter0 = coverage_known_after(ThenEntryCount)
-    ;
-        CondCoverageAfter0 = coverage_unknown
-    ),
-    CondCoverage0 = merge_coverage(get_coverage_before(!.Coverage),
-        CondCoverageAfter0),
-    goal_annotate_coverage(Info, CondGoalPath, CondCoverage0, CondCoverage, 
+    % Step 1:
+    %   Call goal_annotate_coverage for the condition goal.
+    goal_annotate_coverage(Info, CondGoalPath, CoverageBefore0, CondCoverage, 
         Cond0, Cond),
-    split_coverage(CondCoverage, CondCoverageBefore, CondCoverageAfter),
 
-    % Step 3: Infer coverages for the Then and Else goals if unknown.
-    CoverageAfter0 = get_coverage_after(!.Coverage),
-    split_coverage(ThenCoverage1, ThenCoverageBefore1, ThenCoverageAfter1),
+    % Step 2:
+    %   Lookup coverage information for the then and else goals.  Set the
+    %   coverage before the then and else goals.
     (
-        ThenCoverageBefore1 = coverage_unknown,
-        CondCoverageAfter = coverage_known_after(CondCountAfterPrime)
+        coverage_count_after(CondCoverage, CountAfterCond)
     ->
-        ThenCoverageBefore2 = coverage_known_before(CondCountAfterPrime),
-        trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
-            io.format("ITE Set coverage before Then: %d\n", 
-                [i(CondCountAfterPrime)], !IO)
-        )
+        ThenCoverage0 = coverage_known_before(CountAfterCond)
     ;
-        ThenCoverageBefore2 = ThenCoverageBefore1
+        get_branch_coverage(Info, ThenGoalPath, ThenCoverage0)
     ),
-    (
-        ThenCoverageAfter1 = coverage_unknown,
-        CoverageAfter0 = coverage_known_after(CountAfterPrime),
-        ElseCoverageAfter1 = coverage_known_after(ElseCountAfterPrime)
-    ->
-        ThenCoverageAfter2 = 
-            coverage_known_after(CountAfterPrime - ElseCountAfterPrime),
+    get_branch_coverage(Info, ElseGoalPath, ElseCoverage0),
+
         trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
-            io.format("ITE Set coverage after Then: %d - %d\n", 
-                [i(CountAfterPrime), i(ElseCountAfterPrime)], !IO)
-        )
-    ;
-        ThenCoverageAfter2 = ThenCoverageAfter1
+        io.format("ITE Coverage inferred after then and else branches:\n" ++ 
+            "\tWhole: %s\n\tThen: %s\n\tElse: %s\n" ++ 
+            "\tGoalPath %s\n", 
+            [s(string(!.Coverage)), 
+            s(string(ThenCoverage0)), s(string(ElseCoverage0)),
+            s(goal_path_to_string(GoalPath))], !IO)
     ),
-    ThenCoverage2 = merge_coverage(ThenCoverageBefore2, ThenCoverageAfter2),
-    split_coverage(ElseCoverage1, ElseCoverageBefore1, ElseCoverageAfter1),
+    
+    % Step 3:
+    %   Call goal_annotate_coverage for the then and else goals.
+    goal_annotate_coverage(Info, ThenGoalPath, ThenCoverage0, ThenCoverage,
+        Then0, Then),
+    goal_annotate_coverage(Info, ElseGoalPath, ElseCoverage0, ElseCoverage,
+        Else0, Else),
+    
+    % Step 4:
+    %   Calculate the coverage at the end of the entire switch.
     (
-        ElseCoverageBefore1 = coverage_unknown,
-        CondCoverageAfter = coverage_known_after(CondCountAfter),
-        CondCoverageBefore = coverage_known_before(CondCountBefore),
-        detism_get_solutions(CondDetism) = NumSolutions,
-        ( NumSolutions = at_most_zero
-        ; NumSolutions = at_most_one
-        )
-    ->
-        CondFailures = CondCountBefore - CondCountAfter,
-        ElseCoverageBefore2 = coverage_known_before(CondFailures),
-        trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
-            io.format("ITE Set coverage before Else: %d\n", 
-                [i(CondFailures)], !IO)
-        )
+        CoverageBefore0 = coverage_known_before(_),
+        CoverageBefore = CoverageBefore0
     ;
-        ElseCoverageBefore2 = ElseCoverageBefore1
+        CoverageBefore0 = coverage_unknown,
+        CoverageBefore = get_coverage_before(CondCoverage)
     ),
     (
-        ElseCoverageAfter1 = coverage_unknown,
-        CoverageAfter0 = coverage_known_after(CountAfter),
-        ThenCoverageAfter1 = coverage_known_after(ThenCountAfterPrime)
-    ->
-        ElseCoverageAfter2 = 
-            coverage_known_after(CountAfter - ThenCountAfterPrime),
-        trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
-            io.format("ITE Set coverage after Else: %d - %d\n", 
-                [i(CountAfter), i(ThenCountAfterPrime)], !IO)
-        )
-    ;
-        ElseCoverageAfter2 = ElseCoverageAfter1
-    ),
-    ElseCoverage2 = merge_coverage(ElseCoverageBefore2, ElseCoverageAfter2),
-   
-    % Step 4: If more coverage information was inferred then complete the
-    % coverage calculations for any inner goals in Then and Else.
-    ( ThenCoverage1 \= ThenCoverage2 ->
-        goal_annotate_coverage(Info, ThenGoalPath, ThenCoverage2, ThenCoverage,
-            Then0, Then)
-    ;
-        ThenCoverage = ThenCoverage2,
-        % Then1 is the result of the previous call to gaol_annotate_coverage
-        % for the then goal.
-        Then = Then1
-    ),
-    ( ElseCoverage1 \= ElseCoverage2 ->
-        goal_annotate_coverage(Info, ElseGoalPath, ElseCoverage2, ElseCoverage,
-            Else0, Else)
+        CoverageAfter0 = coverage_known_after(_),
+        CoverageAfter = CoverageAfter0
     ;
-        ElseCoverage = ElseCoverage2,
-        % Else1 is the result of the previous call to gaol_annotate_coverage
-        % for the else goal.
-        Else = Else1
-    ),
-   
-    % Finally update the coverage state for the whole switch.
+        CoverageAfter0 = coverage_unknown,
     (
-        get_coverage_after(ThenCoverage) =
-            coverage_known_after(ThenCountAfter),
-        get_coverage_after(ElseCoverage) = 
-            coverage_known_after(ElseCountAfter)
+            coverage_count_after(ThenCoverage, CountAfterThen1),
+            coverage_count_after(ElseCoverage, CountAfterElse1)
     ->
-        CoverageAfter = coverage_known_after(ThenCountAfter + ElseCountAfter),
-        trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
-            io.format("ITE Set coverage after ITE: %d + %d\n", 
-                [i(ThenCountAfter), i(ElseCountAfter)], !IO)
-        )
+            CoverageAfter =
+                coverage_known_after(CountAfterThen1 + CountAfterElse1)
     ;
-        CoverageAfter = get_coverage_after(!.Coverage)
-    ),
-    ( get_coverage_before(CondCoverage) = coverage_known_before(CountBefore) ->
-        CoverageBefore = coverage_known_before(CountBefore),
-        trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] ( 
-            io.format("ITE Set coverage before ITE: %d\n", [i(CountBefore)],
-                !IO)
+            CoverageAfter = coverage_unknown
         )
-    ;
-        CoverageBefore = get_coverage_before(!.Coverage)
     ),
     !:Coverage = merge_coverage(CoverageBefore, CoverageAfter),
+
+    trace [ compile_time(not flag("no_coverage_propagation_assertions")) ]
     require(check_ite_coverage(!.Coverage, CondCoverage, ThenCoverage,
             ElseCoverage, CondDetism), 
         string.format("check_ite_coverage/4 failed\n" ++ 
-            "\tWhole: %s\n\tCond: %s\n\tThen: %s\n\tElse: %s\n",
+                "\tWhole: %s\n\tCond: %s\n\tThen: %s\n\tElse: %s\n" ++ 
+                "\tGoalPath: %s\n",
             [s(string(!.Coverage)), s(string(CondCoverage)),
-            s(string(ThenCoverage)), s(string(ElseCoverage))])).
+                s(string(ThenCoverage)), s(string(ElseCoverage)),
+                s(goal_path_to_string(GoalPath))])).
+
+:- pred not_unify(T::in, T::in) is semidet.
+
+not_unify(A, B) :- not unify(A, B).
 
     % Get the coverage information from a coverage point about the branch
     % referenced by the given goal path.
@@ -1097,29 +1042,25 @@ get_branch_coverage(Info, GoalPath, Cove
 
 negation_annotate_coverage(Info, GoalPath, Coverage0, Coverage,
         NegGoal0, NegGoal) :-
-    split_coverage(Coverage0, CoverageBefore, CoverageAfter0),
-    (
-        CoverageAfter0 = coverage_known_after(CountAfter0),
-        CoverageBefore = coverage_known_before(CountBefore)
-    ->
-        CoverageAfter1 = coverage_known_after(CountBefore - CountAfter0)
-    ;
-        CoverageAfter1 = coverage_unknown
-    ),
-    Coverage1 = merge_coverage(CoverageBefore, CoverageAfter1),
+    split_coverage(Coverage0, CoverageBefore0, CoverageAfter0),
+    Coverage1 = merge_coverage(CoverageBefore0, coverage_unknown),
+    
     NegGoalPath = goal_path_add_at_end(GoalPath, step_neg),
     goal_annotate_coverage(Info, NegGoalPath, Coverage1, Coverage2,
         NegGoal0, NegGoal),
-    CoverageAfter2 = get_coverage_after(Coverage2),
+   
+    CoverageBefore2 = get_coverage_before(Coverage2),
     (
-        CoverageAfter2 = coverage_known_after(CountAfter2),
-        CoverageBefore = coverage_known_before(CountBeforePrime)
-    ->
-        CoverageAfter = coverage_known_after(CountBeforePrime - CountAfter2)
+        CoverageBefore2 = coverage_unknown,
+        CoverageBefore = CoverageBefore0
     ;
-        CoverageAfter = coverage_unknown 
+        CoverageBefore2 = coverage_known_before(_),
+        CoverageBefore = CoverageBefore2
     ),
-    Coverage = merge_coverage(CoverageBefore, CoverageAfter).
+    Coverage = merge_coverage(CoverageBefore, CoverageAfter0),
+    trace [compile_time(flag("debug_coverage_propagation")), io(!IO) ]
+        io.format("Negation: setting negation coverage: %s\n",
+            [s(string(Coverage))], !IO).
         
 :- pred scope_annotate_coverage(coverage_reference_info::in, goal_path::in,
     maybe_cut::in, coverage_info::in, coverage_info::out,
@@ -1127,11 +1068,19 @@ negation_annotate_coverage(Info, GoalPat
 
 scope_annotate_coverage(Info, GoalPath, MaybeCut, !Coverage, 
         ScopedGoal0, ScopedGoal) :-
+    ScopeCoverageAfter0 = get_coverage_after(!.Coverage),
     maybe_cut_discard_solutions(MaybeCut, !Coverage),
     ScopeGoalPath = goal_path_add_at_end(GoalPath, step_scope(MaybeCut)),
     goal_annotate_coverage(Info, ScopeGoalPath, !Coverage, ScopedGoal0,
         ScopedGoal),
-    maybe_cut_discard_solutions(MaybeCut, !Coverage).
+    maybe_cut_discard_solutions(MaybeCut, !Coverage),
+    split_coverage(!.Coverage, ScopeCoverageBefore, ScopeCoverageAfter1),
+    (
+        ScopeCoverageAfter1 = coverage_unknown,
+        !:Coverage = merge_coverage(ScopeCoverageBefore, ScopeCoverageAfter0)
+    ;
+        ScopeCoverageAfter1 = coverage_known_after(_)
+    ).
 
 :- pred maybe_cut_discard_solutions(maybe_cut::in,
     coverage_info::in, coverage_info::out) is det.
@@ -1212,17 +1161,12 @@ check_coverage_regarding_detism(_Coverag
     % Check that the coverages over the switch make sense.  This works only for
     % deterministic switches.
     % 
-    % XXX: Re-write this to work on entry counts for switches that cannot fail
-    % only.
-    %
-:- pred check_switch_coverage(detism_rep::in,
+:- pred check_switch_coverage(switch_can_fail_rep::in,
     list(case_rep(coverage_info))::in, coverage_info::in) is semidet.
 
-check_switch_coverage(Detism, Cases, Coverage) :-
+check_switch_coverage(CanFail, Cases, Coverage) :-
     (
-        ( Detism = det_rep
-        ; Detism = cc_multidet_rep
-        ),
+        CanFail = switch_can_not_fail,
         list.foldl(sum_switch_case_coverage, Cases, yes(0), MaybeSum),
         (
             MaybeSum = yes(Sum),
@@ -1238,13 +1182,7 @@ check_switch_coverage(Detism, Cases, Cov
             MaybeSum = no
         )
     ;
-        ( Detism = semidet_rep
-        ; Detism = multidet_rep
-        ; Detism = nondet_rep
-        ; Detism = cc_nondet_rep
-        ; Detism = failure_rep
-        ; Detism = erroneous_rep
-        )
+        CanFail = switch_can_fail
     ).
 
 :- pred sum_switch_case_coverage(case_rep(coverage_info)::in,
@@ -1316,6 +1254,64 @@ check_ite_coverage(WholeCoverage, CondCo
         true
     ).
 
+:- pred check_coverage_complete(coverage_info::in, goal_expr_rep(T)::in) 
+    is semidet.
+
+check_coverage_complete(coverage_known(_, _), _GoalExpr).
+check_coverage_complete(coverage_known_det(_), _GoalExpr).
+% Uncomment this clause if, in the future, we allow coverage to be incomplete
+% for trivial goals.
+%check_coverage_complete(Coverage, GoalExpr) :-
+%    ( Coverage = coverage_known_before(_)
+%    ; Coverage = coverage_known_after(_)
+%    ; Coverage = coverage_unknown
+%    ),
+%    goal_expr_is_trivial(GoalExpr).
+
+:- pred goal_is_trivial(goal_rep(T)::in) is semidet.
+
+goal_is_trivial(Goal) :-
+    GoalExpr = Goal ^ goal_expr_rep,
+    goal_expr_is_trivial(GoalExpr).
+
+:- pred goal_expr_is_trivial(goal_expr_rep(T)::in) is semidet.
+
+goal_expr_is_trivial(conj_rep(Conjs)) :-
+    list.all_true(goal_is_trivial, Conjs). 
+
+goal_expr_is_trivial(disj_rep(Disjs)) :-
+    list.all_true(goal_is_trivial, Disjs).
+
+goal_expr_is_trivial(switch_rep(_, _, Cases)) :-
+    list.all_true((pred(Case::in) is semidet :-
+        Case = case_rep(_, _, Goal),
+        goal_is_trivial(Goal)), Cases).
+
+goal_expr_is_trivial(ite_rep(Cond, Then, Else)) :-
+    goal_is_trivial(Cond),
+    goal_is_trivial(Then),
+    goal_is_trivial(Else).
+
+goal_expr_is_trivial(negation_rep(SubGoal)) :-
+    goal_is_trivial(SubGoal).
+
+goal_expr_is_trivial(scope_rep(SubGoal, _)) :-
+    goal_is_trivial(SubGoal).
+
+goal_expr_is_trivial(atomic_goal_rep(_, _, _, AtomicGoal)) :-
+    ( AtomicGoal = unify_construct_rep(_, _, _)
+    ; AtomicGoal = unify_deconstruct_rep(_, _, _)
+    ; AtomicGoal = partial_deconstruct_rep(_, _, _)
+    ; AtomicGoal = partial_construct_rep(_, _, _)
+    ; AtomicGoal = unify_assign_rep(_, _)
+    ; AtomicGoal = cast_rep(_, _)
+    ; AtomicGoal = unify_simple_test_rep(_, _)
+    % Built-in calls are probably cheap enough to consider to be trivial.
+    ; AtomicGoal = builtin_call_rep(_, _, _)
+    ; AtomicGoal = pragma_foreign_code_rep(_)
+    ; AtomicGoal = event_call_rep(_, _) 
+    ).
+
 %----------------------------------------------------------------------------%
 %
 % Coverage information helper predicates.
@@ -1348,13 +1344,12 @@ propagate_det_coverage(GoalPath, !Covera
         !.Coverage = coverage_known_det(_)
     ;
         !.Coverage = coverage_known(Before, After),
-        ( Before = After ->
+        trace [compile_time(not flag("no_coverage_propagation_assertions"))]
+            require(unify(Before, After), 
+                format("Coverage before /= after for a det goal: %s, GP: %s",
+                    [s(string(!.Coverage)), s(goal_path_to_string(GoalPath))])),
             !:Coverage = coverage_known_det(Before)
         ;
-            error(format("Coverage before /= after for a det goal: %s, GP: %s",
-                [s(string(!.Coverage)), s(goal_path_to_string(GoalPath))]))
-        )
-    ;
         ( !.Coverage = coverage_known_before(Coverage)
         ; !.Coverage = coverage_known_after(Coverage)
         ),
@@ -1364,10 +1359,16 @@ propagate_det_coverage(GoalPath, !Covera
     % If the determinism is deterministic or cc_multi use
     % propagate_det_coverage.
     %
-:- pred maybe_propagate_det_coverage(detism_rep::in, goal_path::in, 
+:- pred propagate_coverage(detism_rep::in, goal_path::in, 
     coverage_info::in, coverage_info::out) is det.
 
-maybe_propagate_det_coverage(Detism, GoalPath, !Coverage) :-
+propagate_coverage(Detism, GoalPath, !Coverage) :-
+    % TODO: Infer that if a goal has a coverage of exactly 0 before it, then it
+    % must have a coverage of exactly 0 after it.  And that a goal that cannot
+    % fail that has a coverage of 0 after it, must have a coverage of 0 before
+    % it - Since the coverage profiling and propagation algorithms are already
+    % complete this isn't required.  It should be considered if we choose not
+    % to calculate coverage for trivial goals.
     (
         ( Detism = det_rep
         ; Detism = cc_multidet_rep ),
@@ -1381,9 +1382,12 @@ maybe_propagate_det_coverage(Detism, Goa
     ;
         Detism = cc_nondet_rep
     ;
-        Detism = erroneous_rep
-    ;
-        Detism = failure_rep
+        ( Detism = erroneous_rep
+        ; Detism = failure_rep
+        ),
+        % Execution never reaches the end of these goals.
+        CoverageBefore = get_coverage_before(!.Coverage),
+        !:Coverage = merge_coverage(CoverageBefore, coverage_known_after(0))
     ).
 
     % Information about the coverage before a goal only.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20080925/c63e13ad/attachment.sig>


More information about the reviews mailing list