[m-rev.] diff: higher order specialization

Zoltan Somogyi zs at cs.mu.OZ.AU
Mon Aug 29 16:38:31 AEST 2005


Optimize higher order calls by providing variants of the relevant code that
are specialized to a given number of explicitly given arguments.

runtime/mercury_ho_call.[ch]:
	Define variants of do_call_closure and do_call_class_method
	specialized to 0, 1, 2 or 3 explicit input arguments. Apart from
	not needing to be passed the number of explicit input arguments
	in a register, these avoid some runtime tests and unroll loops.

	Harmonize the variable names used in the do_call_closure and
	do_call_class_method variants. Since they are near-copies of each
	other, factor out their documentation. (Factoring out the code itself
	would be possible, but would not make maintenance easier and would make
	the code harder to read.)

	Provide a mechanism to gather statistics about the numbers of hidden
	and explicit arguments if the macro MR_DO_CALL_STATS is set.

compiler/options.m:
	Add options that specify how many of these variants exist. These
	provide the necessary synchronization between the runtime and the
	compiler. They are not meant to be set from the command line, even by
	implementors.

runtime/mercury_conf_params.h:
	Document MR_DO_CALL_STATS.

runtime/mercury_wrapper.c:
	If MR_DO_CALL_STATS is set, print the gathered statistics when
	execution ends.

runtime/mecury_mm_own_stack.c:
	Fix a typo that prevented the stage2 library from linking in jump.gc
	grade.

compiler/llds.m:
	Provide a way to represent the labels of the new specialized variants.

compiler/llds__out.m:
	Output the labels of the new specialized variants if required.

	Convert to four-space indentation.

compiler/call_gen.m:
	Call the specialized variants of do_call_closure or
	do_call_class_method if they are applicable.

code_info/follow_vars.m:
code_info/interval.m:
code_info/tupling.m:
	Conform to the change in call_gen.m.

code_info/dupproc.m:
code_info/exprn_aux.m:
code_info/livemap.m:
code_info/opt_util.m:
	Conform to the change in llds.m.

compiler/code_info.m:
	Minor style cleanups.

tools/bootcheck:
	Enable the collection of statistics from the compilation of stage 3
	and the test cases, for use when the stage 2 is built with
	MR_DO_CALL_STATS enabled.

tools/ho_call_stats:
	A new script to analyze the statistics collected.

tools/makebatch:
	Add a new option --save-stage2-on-no-compiler, which is a variant of
	the existing option --save-stage2-on-error.

Zoltan.

cvs diff: Diffing .
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/call_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/call_gen.m,v
retrieving revision 1.164
diff -u -b -r1.164 call_gen.m
--- compiler/call_gen.m	12 Aug 2005 05:14:08 -0000	1.164
+++ compiler/call_gen.m	27 Aug 2005 04:03:45 -0000
@@ -23,6 +23,7 @@
 :- import_module hlds__code_model.
 :- import_module hlds__hlds_goal.
 :- import_module hlds__hlds_pred.
+:- import_module libs__globals.
 :- import_module ll_backend__code_info.
 :- import_module ll_backend__llds.
 :- import_module parse_tree__prog_data.
@@ -43,11 +44,16 @@
     list(prog_var)::in, code_tree::out, code_info::in, code_info::out)
     is det.
 
-    % call_gen__generic_call_info(CodeModel, GenericCall,
-    %   CodeAddr, FirstImmediateInputReg).
+:- type known_call_variant
+    --->    known_num
+    ;       unknown.
+
+    % call_gen__generic_call_info(Globals, GenericCall, NumImmediateInputArgs,
+    %   CodeAddr, SpecifierArgInfos, FirstImmediateInputReg, HoCallVariant).
     %
-:- pred call_gen__generic_call_info(code_model::in, generic_call::in,
-    code_addr::out, assoc_list(prog_var, arg_info)::out, int::out) is det.
+:- pred call_gen__generic_call_info(globals::in, generic_call::in, int::in,
+    code_addr::out, assoc_list(prog_var, arg_info)::out, int::out,
+    known_call_variant::out) is det.
 
 :- pred call_gen__input_arg_locs(assoc_list(prog_var, arg_info)::in,
     assoc_list(prog_var, arg_loc)::out) is det.
@@ -70,7 +76,6 @@
 :- import_module hlds__hlds_llds.
 :- import_module hlds__hlds_module.
 :- import_module hlds__instmap.
-:- import_module libs__globals.
 :- import_module libs__options.
 :- import_module libs__tree.
 :- import_module ll_backend__code_util.
@@ -172,22 +177,23 @@
         Modes, Det, GoalInfo, Code, !CI) :-
     Types = list__map(code_info__variable_type(!.CI), Args),
 
+    code_info__get_module_info(!.CI, ModuleInfo),
+    arg_info__compute_in_and_out_vars(ModuleInfo, Args, Modes, Types,
+        InVars, OutVars),
+    module_info_globals(ModuleInfo, Globals),
+    call_gen__generic_call_info(Globals, GenericCall, length(InVars),
+        CodeAddr, SpecifierArgInfos, FirstImmInput, HoCallVariant),
     determinism_to_code_model(Det, CodeModel),
-    call_gen__generic_call_info(CodeModel, GenericCall,
-        CodeAddr, SpecifierArgInfos, FirstImmInput),
     ( CodeModel = model_semi ->
         FirstOutput = 2
     ;
         FirstOutput = 1
     ),
 
-    code_info__get_module_info(!.CI, ModuleInfo),
-    arg_info__compute_in_and_out_vars(ModuleInfo, Args, Modes, Types,
-        InVars, OutVars),
-    call_gen__give_vars_consecutive_arg_infos(InVars, FirstImmInput,
-        top_in, InVarArgInfos),
-    call_gen__give_vars_consecutive_arg_infos(OutVars, FirstOutput,
-        top_out, OutArgsInfos),
+    give_vars_consecutive_arg_infos(InVars, FirstImmInput, top_in,
+        InVarArgInfos),
+    give_vars_consecutive_arg_infos(OutVars, FirstOutput, top_out,
+        OutArgsInfos),
     list__append(SpecifierArgInfos, InVarArgInfos, InArgInfos),
     list__append(InArgInfos, OutArgsInfos, ArgInfos),
 
@@ -201,8 +207,8 @@
         % registers. Setting up these arguments last results in
         % slightly more efficient code, since we can use their
         % registers when placing the variables.
-    call_gen__generic_call_nonvar_setup(GenericCall, InVars, OutVars,
-        NonVarCode, !CI),
+    call_gen__generic_call_nonvar_setup(GenericCall, HoCallVariant,
+        InVars, OutVars, NonVarCode, !CI),
 
     call_gen__extra_livevals(FirstImmInput, ExtraLiveVals),
     set__insert_list(LiveVals0, ExtraLiveVals, LiveVals),
@@ -260,15 +266,54 @@
         ExtraLiveVals = []
     ).
 
-call_gen__generic_call_info(_, higher_order(PredVar, _, _, _),
-        do_call_closure, [PredVar - arg_info(1, top_in)], 3).
-call_gen__generic_call_info(_, class_method(TCVar, _, _, _),
-        do_call_class_method, [TCVar - arg_info(1, top_in)], 4).
+call_gen__generic_call_info(Globals, GenericCall, NumInputArgs, CodeAddr,
+        SpecifierArgInfos, FirstImmediateInputReg, HoCallVariant) :-
+    (
+        GenericCall = higher_order(PredVar, _, _, _),
+        SpecifierArgInfos = [PredVar - arg_info(1, top_in)],
+        globals__lookup_int_option(Globals,
+            max_specialized_do_call_closure, MaxSpec),
+        (
+            MaxSpec >= 0,
+            NumInputArgs =< MaxSpec
+        ->
+            CodeAddr = do_call_closure(specialized_known(NumInputArgs)),
+            HoCallVariant = known_num,
+            FirstImmediateInputReg = 2
+        ;
+            CodeAddr = do_call_closure(generic),
+            HoCallVariant = unknown,
+            FirstImmediateInputReg = 3
+        )
+    ;
+        GenericCall = class_method(TCVar, _, _, _),
+        SpecifierArgInfos = [TCVar - arg_info(1, top_in)],
+        globals__lookup_int_option(Globals,
+            max_specialized_do_call_class_method, MaxSpec),
+        (
+            MaxSpec >= 0,
+            NumInputArgs =< MaxSpec
+        ->
+            CodeAddr = do_call_class_method(specialized_known(NumInputArgs)),
+            HoCallVariant = known_num,
+            FirstImmediateInputReg = 3
+        ;
+            CodeAddr = do_call_class_method(generic),
+            HoCallVariant = unknown,
+            FirstImmediateInputReg = 4
+        )
+    ;
     % Casts are generated inline.
-call_gen__generic_call_info(_, cast(_), do_not_reached, [], 1).
-call_gen__generic_call_info(_, aditi_builtin(_, _), _, _, _) :-
+        GenericCall = cast(_),
+        CodeAddr = do_not_reached,
+        SpecifierArgInfos = [],
+        FirstImmediateInputReg = 1,
+        HoCallVariant = unknown     % dummy; not used
+    ;
+        GenericCall = aditi_builtin(_, _),
     % These should have been transformed into normal calls.
-    error("call_gen__generic_call_info: aditi_builtin").
+        unexpected(this_file, "generic_call_info: aditi_builtin")
+    ).
 
     % Some of the values that generic call passes to the dispatch routine
     % to specify what code is being indirectly called come from HLDS
@@ -283,19 +328,34 @@
     % indirectly called code's identifier that come from constants.
     %
 :- pred call_gen__generic_call_nonvar_setup(generic_call::in,
-    list(prog_var)::in, list(prog_var)::in, code_tree::out,
-    code_info::in, code_info::out) is det.
+    known_call_variant::in, list(prog_var)::in, list(prog_var)::in,
+    code_tree::out, code_info::in, code_info::out) is det.
 
 call_gen__generic_call_nonvar_setup(higher_order(_, _, _, _),
-        InVars, _OutVars, Code, !CI) :-
+        HoCallVariant, InVars, _OutVars, Code, !CI) :-
+    (
+        HoCallVariant = known_num,
+        Code = empty
+    ;
+        HoCallVariant = unknown,
     code_info__clobber_regs([reg(r, 2)], !CI),
     list__length(InVars, NInVars),
     Code = node([
         assign(reg(r, 2), const(int_const(NInVars))) -
             "Assign number of immediate input arguments"
-    ]).
+        ])
+    ).
 call_gen__generic_call_nonvar_setup(class_method(_, Method, _, _),
-        InVars, _OutVars, Code, !CI) :-
+        HoCallVariant, InVars, _OutVars, Code, !CI) :-
+    (
+        HoCallVariant = known_num,
+        code_info__clobber_regs([reg(r, 2)], !CI),
+        Code = node([
+            assign(reg(r, 2), const(int_const(Method))) -
+                "Index of class method in typeclass info"
+        ])
+    ;
+        HoCallVariant = unknown,
     code_info__clobber_regs([reg(r, 2), reg(r, 3)], !CI),
     list__length(InVars, NInVars),
     Code = node([
@@ -303,10 +363,11 @@
             "Index of class method in typeclass info",
         assign(reg(r, 3), const(int_const(NInVars))) -
             "Assign number of immediate input arguments"
-    ]).
-call_gen__generic_call_nonvar_setup(cast(_), _, _, _, !CI) :-
+        ])
+    ).
+call_gen__generic_call_nonvar_setup(cast(_), _, _, _, _, !CI) :-
     unexpected(this_file, "generic_call_nonvar_setup: cast").
-call_gen__generic_call_nonvar_setup(aditi_builtin(_, _), _, _, _, !CI) :-
+call_gen__generic_call_nonvar_setup(aditi_builtin(_, _), _, _, _, _, !CI) :-
     % These should have been transformed into normal calls.
     unexpected(this_file, "generic_call_nonvar_setup: aditi_builtin").
 
@@ -578,15 +639,15 @@
 
 %---------------------------------------------------------------------------%
 
-:- pred call_gen__give_vars_consecutive_arg_infos(list(prog_var)::in, int::in,
+:- pred give_vars_consecutive_arg_infos(list(prog_var)::in, int::in,
     arg_mode::in, assoc_list(prog_var, arg_info)::out) is det.
 
-call_gen__give_vars_consecutive_arg_infos([], _N, _M, []).
-call_gen__give_vars_consecutive_arg_infos([Var | Vars], N0, ArgMode,
+give_vars_consecutive_arg_infos([], _N, _M, []).
+give_vars_consecutive_arg_infos([Var | Vars], N0, ArgMode,
         [Var - ArgInfo | ArgInfos]) :-
     ArgInfo = arg_info(N0, ArgMode),
     N1 = N0 + 1,
-    call_gen__give_vars_consecutive_arg_infos(Vars, N1, ArgMode, ArgInfos).
+    give_vars_consecutive_arg_infos(Vars, N1, ArgMode, ArgInfos).
 
 %---------------------------------------------------------------------------%
 
Index: compiler/code_info.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/code_info.m,v
retrieving revision 1.301
diff -u -b -r1.301 code_info.m
--- compiler/code_info.m	22 Jul 2005 12:31:52 -0000	1.301
+++ compiler/code_info.m	26 Aug 2005 01:30:32 -0000
@@ -3504,8 +3504,7 @@
 
 code_info__clear_all_registers(OkToDeleteAny, !CI) :-
     code_info__get_var_locn_info(!.CI, VarLocnInfo0),
-    var_locn__clobber_all_regs(OkToDeleteAny,
-        VarLocnInfo0, VarLocnInfo),
+    var_locn__clobber_all_regs(OkToDeleteAny, VarLocnInfo0, VarLocnInfo),
     code_info__set_var_locn_info(VarLocnInfo, !CI).
 
 code_info__clobber_regs(Regs, !CI) :-
@@ -3573,10 +3572,8 @@
 :- implementation.
 
 code_info__generate_call_vn_livevals(CI, InputArgLocs, OutputArgs, LiveVals) :-
-    code_info__generate_call_stack_vn_livevals(CI, OutputArgs,
-        StackLiveVals),
-    code_info__generate_input_var_vn(InputArgLocs, StackLiveVals,
-        LiveVals).
+    code_info__generate_call_stack_vn_livevals(CI, OutputArgs, StackLiveVals),
+    code_info__generate_input_var_vn(InputArgLocs, StackLiveVals, LiveVals).
 
 :- pred code_info__generate_call_stack_vn_livevals(code_info::in,
     set(prog_var)::in, set(lval)::out) is det.
@@ -3641,7 +3638,8 @@
 code_info__generate_resume_layout(Label, ResumeMap, !CI) :-
     code_info__get_globals(!.CI, Globals),
     globals__lookup_bool_option(Globals, agc_stack_layout, AgcStackLayout),
-    ( AgcStackLayout = yes ->
+    (
+        AgcStackLayout = yes,
         code_info__get_active_temps_data(!.CI, Temps),
         code_info__get_instmap(!.CI, InstMap),
         code_info__get_proc_info(!.CI, ProcInfo),
@@ -3650,7 +3648,7 @@
             ProcInfo, ModuleInfo, Layout),
         code_info__add_resume_layout_for_label(Label, Layout, !CI)
     ;
-        true
+        AgcStackLayout = no
     ).
 
 %---------------------------------------------------------------------------%
Index: compiler/dupproc.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/dupproc.m,v
retrieving revision 1.1
diff -u -b -r1.1 dupproc.m
--- compiler/dupproc.m	8 Jul 2005 04:22:01 -0000	1.1
+++ compiler/dupproc.m	25 Aug 2005 12:10:11 -0000
@@ -350,10 +350,10 @@
 		CodeAddr = do_trace_redo_fail_deep,
 		StdCodeAddr = CodeAddr
 	;
-		CodeAddr = do_call_closure,
+		CodeAddr = do_call_closure(_),
 		StdCodeAddr = CodeAddr
 	;
-		CodeAddr = do_call_class_method,
+		CodeAddr = do_call_class_method(_),
 		StdCodeAddr = CodeAddr
 	;
 		CodeAddr = do_not_reached,
Index: compiler/exprn_aux.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/exprn_aux.m,v
retrieving revision 1.57
diff -u -b -r1.57 exprn_aux.m
--- compiler/exprn_aux.m	8 Jul 2005 04:22:01 -0000	1.57
+++ compiler/exprn_aux.m	25 Aug 2005 12:10:23 -0000
@@ -165,8 +165,8 @@
 exprn_aux__addr_is_constant(do_fail, _, no).
 exprn_aux__addr_is_constant(do_trace_redo_fail_shallow, _, no).
 exprn_aux__addr_is_constant(do_trace_redo_fail_deep, _, no).
-exprn_aux__addr_is_constant(do_call_closure, _, no).
-exprn_aux__addr_is_constant(do_call_class_method, _, no).
+exprn_aux__addr_is_constant(do_call_closure(_), _, no).
+exprn_aux__addr_is_constant(do_call_class_method(_), _, no).
 exprn_aux__addr_is_constant(do_not_reached, _, no).
 
 :- pred exprn_aux__label_is_constant(label::in, bool::in, bool::in, bool::out)
Index: compiler/follow_vars.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/follow_vars.m,v
retrieving revision 1.72
diff -u -b -r1.72 follow_vars.m
--- compiler/follow_vars.m	12 Aug 2005 05:14:09 -0000	1.72
+++ compiler/follow_vars.m	25 Aug 2005 14:59:35 -0000
@@ -236,8 +236,9 @@
 			ArgInfos, ArgsInfos),
 		arg_info__partition_args(ArgsInfos, InVarInfos, _),
 		assoc_list__keys(InVarInfos, InVars),
-		call_gen__generic_call_info(CodeModel, GenericCall, _,
-			SpecifierArgInfos, FirstInput),
+		module_info_globals(ModuleInfo, Globals),
+		call_gen__generic_call_info(Globals, GenericCall,
+			length(InVars), _, SpecifierArgInfos, FirstInput, _),
 		find_follow_vars_from_arginfo(SpecifierArgInfos,
 			map__init, !:FollowVarsMap, 1, _),
 		find_follow_vars_from_sequence(InVars, FirstInput,
Index: compiler/interval.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/interval.m,v
retrieving revision 1.5
diff -u -b -r1.5 interval.m
--- compiler/interval.m	12 Aug 2005 05:14:12 -0000	1.5
+++ compiler/interval.m	25 Aug 2005 14:58:44 -0000
@@ -279,7 +279,7 @@
 	build_interval_info_in_goal(Goal, !IntervalInfo, !Acc).
 
 build_interval_info_in_goal(Goal - GoalInfo, !IntervalInfo, !Acc) :-
-	Goal = generic_call(GenericCall, ArgVars, ArgModes, Detism),
+	Goal = generic_call(GenericCall, ArgVars, ArgModes, _Detism),
 	goal_info_get_maybe_need_across_call(GoalInfo, MaybeNeedAcrossCall),
 	IntParams = !.IntervalInfo ^ interval_params,
 	VarTypes = IntParams ^ var_types,
@@ -287,15 +287,15 @@
 	ModuleInfo = IntParams ^ module_info,
 	arg_info__compute_in_and_out_vars(ModuleInfo, ArgVars,
 		ArgModes, ArgTypes, InputArgs, _OutputArgs),
-	determinism_to_code_model(Detism, CodeModel),
 
 	% Casts are generated inline.
 	( GenericCall = cast(_) ->
 		require_in_regs(InputArgs, !IntervalInfo),
 		require_access(InputArgs, !IntervalInfo)
 	;
-		call_gen__generic_call_info(CodeModel, GenericCall, _,
-			GenericVarsArgInfos, _),
+		module_info_globals(ModuleInfo, Globals),
+		call_gen__generic_call_info(Globals, GenericCall,
+			length(InputArgs), _, GenericVarsArgInfos, _, _),
 		assoc_list__keys(GenericVarsArgInfos, GenericVars),
 		list__append(GenericVars, InputArgs, Inputs),
 		build_interval_info_at_call(Inputs,
Index: compiler/livemap.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/livemap.m,v
retrieving revision 1.63
diff -u -b -r1.63 livemap.m
--- compiler/livemap.m	22 Mar 2005 06:40:03 -0000	1.63
+++ compiler/livemap.m	25 Aug 2005 12:10:36 -0000
@@ -358,8 +358,8 @@
 livemap__special_code_addr(do_trace_redo_fail_shallow, no).
 livemap__special_code_addr(do_trace_redo_fail_deep, no).
 livemap__special_code_addr(do_fail, no).
-livemap__special_code_addr(do_call_closure, no).
-livemap__special_code_addr(do_call_class_method, no).
+livemap__special_code_addr(do_call_closure(_), no).
+livemap__special_code_addr(do_call_class_method(_), no).
 livemap__special_code_addr(do_not_reached, no).
 
 %-----------------------------------------------------------------------------%
Index: compiler/llds.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/llds.m,v
retrieving revision 1.314
diff -u -b -r1.314 llds.m
--- compiler/llds.m	29 Aug 2005 03:22:19 -0000	1.314
+++ compiler/llds.m	29 Aug 2005 06:11:12 -0000
@@ -884,9 +884,23 @@
                                     % then fails. The shallow variety only does
                                     % this if the from_full flag was set on
                                     % entry to the given procedure.
-    ;       do_call_closure
-    ;       do_call_class_method
+    ;       do_call_closure(ho_call_variant)
+    ;       do_call_class_method(ho_call_variant)
+
     ;       do_not_reached.         % We should never jump to this address.
+
+:- type ho_call_variant
+    --->    generic                 % This calls for the use of one of
+                                    % do_call_closure_compact and
+                                    % do_call_class_method_compact,
+                                    % which work for any number of visible
+                                    % input arguments.
+
+    ;       specialized_known(int). % If the integer is N, this calls for
+                                    % the use of do_call_closure_N or
+                                    % do_call_class_method_N. These are
+                                    % specialized to assume N visible
+                                    % input arguments.
 
     % A tag (used in mkword, create and field expressions and in incr_hp
     % instructions) is a small integer.
Index: compiler/llds_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/llds_out.m,v
retrieving revision 1.252
diff -u -b -r1.252 llds_out.m
--- compiler/llds_out.m	29 Aug 2005 03:22:19 -0000	1.252
+++ compiler/llds_out.m	29 Aug 2005 06:17:42 -0000
@@ -1,4 +1,6 @@
 %-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
 % Copyright (C) 1996-2005 The University of Melbourne.
 % This file may only be copied under the terms of the GNU General
 % Public License - see the file COPYING in the Mercury distribution.
@@ -35,26 +37,26 @@
 	% --split-c-files option. The second argument gives the set of
 	% labels that have layout structures. The third gives the Aditi-RL
 	% code for the module.
-
+    %
 :- pred output_llds(c_file::in, list(complexity_proc_info)::in,
 	map(label, data_addr)::in, maybe(rl_file)::in, io::di, io::uo) is det.
 
 	% output_rval_decls(Rval, DeclSet0, DeclSet) outputs the declarations
 	% of any static constants, etc. that need to be declared before
 	% output_rval(Rval) is called.
-
+    %
 :- pred output_rval_decls(rval::in, decl_set::in, decl_set::out,
 	io::di, io::uo) is det.
 
 	% output an rval (not converted to any particular type,
 	% but instead output as its "natural" type)
-
+    %
 :- pred output_rval(rval::in, io::di, io::uo) is det.
 
 	% output_code_addr_decls(CodeAddr, ...) outputs the declarations of any
 	% extern symbols, etc. that need to be declared before
 	% output_code_addr(CodeAddr) is called.
-
+    %
 :- pred output_code_addr_decls(code_addr::in, decl_set::in, decl_set::out,
 	io::di, io::uo) is det.
 
@@ -63,7 +65,7 @@
 	% output_data_addr_decls(DataAddr, ...) outputs the declarations of
 	% any static constants, etc. that need to be declared before
 	% output_data_addr(DataAddr) is called.
-
+    %
 :- pred output_data_addr_decls(data_addr::in, string::in, string::in,
 	int::in, int::out, decl_set::in, decl_set::out, io::di, io::uo) is det.
 
@@ -79,48 +81,53 @@
 	%	BeingDefined):
 	% Return a C string that gives the storage class appropriate for the
 	% definition of a global variable with the specified properties.
-
+    %
 :- func c_data_linkage_string(globals, linkage, bool, bool) = string.
 
 	% Given a boolean that states whether a data item includes code
 	% addresses or not, return a C string that gives its "const-ness".
-
+    %
 :- pred c_data_const_string(globals::in, bool::in, string::out) is det.
 
-	% Convert an lval to a string description of that lval.
+    % Return the suffix after do_call_closure_ or do_call_class_method_
+    % represented by the given variant.
+    %
+:- func ho_call_variant_to_string(ho_call_variant) = string.
 
+    % Convert an lval to a string description of that lval.
+    %
 :- pred llds_out__lval_to_string(lval::in, string::out) is semidet.
 
 	% Convert a register to a string description of that register.
-
+    %
 :- pred llds_out__reg_to_string(reg_type::in, int::in, string::out) is det.
 
 	% Convert a binary operator to a string description of that operator.
-
+    %
 :- pred llds_out__binary_op_to_string(binary_op::in, string::out) is det.
 
 	% Output an instruction and (if the third arg is yes) the comment.
 	% This predicate is provided for debugging use only.
-
-:- pred output_instruction_and_comment(instr::in, string::in, bool::in,
+    %
+:- pred output_debug_instruction_and_comment(instr::in, string::in, bool::in,
 	io::di, io::uo) is det.
 
 	% Output an instruction.
 	% This predicate is provided for debugging use only.
-
-:- pred output_instruction(instr::in, io::di, io::uo) is det.
+    %
+:- pred output_debug_instruction(instr::in, io::di, io::uo) is det.
 
 	% Output a label (used by garbage collection).
-
+    %
 :- pred output_label(label::in, io::di, io::uo) is det.
 
 	% Output a label without the standard mercury__ prefix.
-
+    %
 :- pred output_label(label::in, bool::in, io::di, io::uo) is det.
 
 	% Convert a label to a C string. The boolean controls whether
 	% a prefix ("mercury__") is added to the string.
-
+    %
 :- func llds_out__label_to_c_string(label, bool) = string.
 
 	% The following are exported to rtti_out. It may be worthwhile
@@ -137,9 +144,9 @@
 
 :- type decl_set.
 
-% Every time we emit a declaration for a symbol, we insert it into the
-% set of symbols we've already declared.  That way, we avoid generating
-% the same symbol twice, which would cause an error in the C code.
+    % Every time we emit a declaration for a symbol, we insert it into the
+    % set of symbols we've already declared.  That way, we avoid generating
+    % the same symbol twice, which would cause an error in the C code.
 
 :- pred decl_set_init(decl_set::out) is det.
 
@@ -202,6 +209,7 @@
 :- import_module set_tree234.
 :- import_module std_util.
 :- import_module string.
+:- import_module svmulti_map.
 :- import_module term.
 :- import_module varset.
 
@@ -221,42 +229,36 @@
 %-----------------------------------------------------------------------------%
 
 output_llds(C_File, ComplexityProcs, StackLayoutLabels, MaybeRLFile, !IO) :-
-	C_File = c_file(ModuleName, C_HeaderInfo,
-		UserForeignCodes, Exports, Vars, Datas, Modules,
-		UserInitPredCNames),
+    C_File = c_file(ModuleName, C_HeaderInfo, UserForeignCodes, Exports, Vars,
+        Datas, Modules, UserInitPredCNames),
 	globals__io_lookup_bool_option(split_c_files, SplitFiles, !IO),
 	(
 		SplitFiles = yes,
-		module_name_to_file_name(ModuleName, ".dir", yes, ObjDirName,
-			!IO),
+        module_name_to_file_name(ModuleName, ".dir", yes, ObjDirName, !IO),
 		dir__make_directory(ObjDirName, _, !IO),
 
 		output_split_c_file_init(ModuleName, Modules, Datas, Vars,
 			ComplexityProcs, StackLayoutLabels, MaybeRLFile, 
 			UserInitPredCNames, !IO),
 		output_split_user_foreign_codes(UserForeignCodes, ModuleName,
-			C_HeaderInfo, ComplexityProcs, StackLayoutLabels,
-			1, Num1, !IO),
+            C_HeaderInfo, ComplexityProcs, StackLayoutLabels, 1, Num1, !IO),
 		output_split_c_exports(Exports, ModuleName,
-			C_HeaderInfo, ComplexityProcs, StackLayoutLabels,
-			Num1, Num2, !IO),
+            C_HeaderInfo, ComplexityProcs, StackLayoutLabels, Num1, Num2, !IO),
 		output_split_comp_gen_c_vars(Vars, ModuleName,
-			C_HeaderInfo, ComplexityProcs, StackLayoutLabels,
-			Num2, Num3, !IO),
+            C_HeaderInfo, ComplexityProcs, StackLayoutLabels, Num2, Num3, !IO),
 		output_split_comp_gen_c_datas(Datas, ModuleName,
-			C_HeaderInfo, ComplexityProcs, StackLayoutLabels,
-			Num3, Num4, !IO),
+            C_HeaderInfo, ComplexityProcs, StackLayoutLabels, Num3, Num4, !IO),
 		output_split_comp_gen_c_modules(Modules, ModuleName,
-			C_HeaderInfo, ComplexityProcs, StackLayoutLabels,
-			Num4, Num, !IO),
+            C_HeaderInfo, ComplexityProcs, StackLayoutLabels, Num4, Num, !IO),
 
-		compile_target_code__write_num_split_c_files(ModuleName,
-			Num, Succeeded, !IO),
-		( Succeeded = no ->
-			compile_target_code__remove_split_c_output_files(
-				ModuleName, Num, !IO)
+        compile_target_code__write_num_split_c_files(ModuleName, Num,
+            Succeeded, !IO),
+        (
+            Succeeded = no,
+            compile_target_code__remove_split_c_output_files(ModuleName, Num,
+                !IO)
 		;
-			true
+            Succeeded = yes
 		)
 	;
 		SplitFiles = no,
@@ -288,8 +290,7 @@
 output_split_c_exports([], _, _, _, _, !Num, !IO).
 output_split_c_exports([Export | Exports], ModuleName, C_HeaderLines,
 		ComplexityProcs, StackLayoutLabels, !Num, !IO) :-
-	CFile = c_file(ModuleName, C_HeaderLines, [], [Export], [], [], [],
-		[]),
+    CFile = c_file(ModuleName, C_HeaderLines, [], [Export], [], [], [], []),
 	output_single_c_file(CFile, yes(!.Num), ComplexityProcs,
 		StackLayoutLabels, no, !IO),
 	!:Num = !.Num + 1,
@@ -334,8 +335,7 @@
 output_split_comp_gen_c_modules([], _, _, _, _, !Num, !IO).
 output_split_comp_gen_c_modules([Module | Modules], ModuleName, C_HeaderLines,
 		ComplexityProcs, StackLayoutLabels, !Num, !IO) :-
-	CFile = c_file(ModuleName, C_HeaderLines, [], [], [], [], [Module],
-		[]),
+    CFile = c_file(ModuleName, C_HeaderLines, [], [], [], [], [Module], []),
 	output_single_c_file(CFile, yes(!.Num), ComplexityProcs,
 		StackLayoutLabels, no, !IO),
 	!:Num = !.Num + 1,
@@ -413,10 +413,11 @@
 output_single_c_file(CFile, SplitFiles, ComplexityProcs, StackLayoutLabels,
 		MaybeRLFile, !IO) :-
 	CFile = c_file(ModuleName, _, _, _, _, _, _, _),
-	( SplitFiles = yes(Num) ->
-		module_name_to_split_c_file_name(ModuleName, Num, ".c",
-			FileName, !IO)
+    (
+        SplitFiles = yes(Num),
+        module_name_to_split_c_file_name(ModuleName, Num, ".c", FileName, !IO)
 	;
+        SplitFiles = no,
 		module_name_to_file_name(ModuleName, ".c", yes, FileName, !IO)
 	),
 	io__open_output(FileName, Result, !IO),
@@ -424,8 +425,7 @@
 		Result = ok(FileStream),
 		decl_set_init(DeclSet0),
 		do_output_single_c_file(CFile, SplitFiles, ComplexityProcs,
-			StackLayoutLabels, MaybeRLFile, 
-			FileStream, DeclSet0, _, !IO),
+            StackLayoutLabels, MaybeRLFile, FileStream, DeclSet0, _, !IO),
 		io__close_output(FileStream, !IO)
 	;
 		Result = error(Error),
@@ -451,8 +451,7 @@
 		Vars, Datas, Modules, UserInitPredCNames),
 	library__version(Version),
 	io__set_output_stream(FileStream, OutputStream, !IO),
-	module_name_to_file_name(ModuleName, ".m", no, SourceFileName,
-		!IO),
+    module_name_to_file_name(ModuleName, ".m", no, SourceFileName, !IO),
 	output_c_file_intro_and_grade(SourceFileName, Version, !IO),
 	(
 		SplitFiles = yes(_)
@@ -477,8 +476,7 @@
 	list__foldl2(output_common_data_defn, CommonDatas, !DeclSet, !IO),
 	list__foldl2(output_rtti_data_defn, RttiDatas, !DeclSet, !IO),
 	order_layout_datas(LayoutDatas, OrderedLayoutDatas),
-	list__foldl2(output_layout_data_defn, OrderedLayoutDatas,
-		!DeclSet, !IO),
+    list__foldl2(output_layout_data_defn, OrderedLayoutDatas, !DeclSet, !IO),
 
 	list__foldl2(output_comp_gen_c_module(StackLayoutLabels), Modules,
 		!DeclSet, !IO),
@@ -522,8 +520,7 @@
 	;
 		!:OtherLayouts = [Layout | !.OtherLayouts]
 	),
-	order_layout_datas_2(Layouts, !ProcLayouts, !LabelLayouts,
-		!OtherLayouts).
+    order_layout_datas_2(Layouts, !ProcLayouts, !LabelLayouts, !OtherLayouts).
 
 :- pred output_c_module_init_list(module_name::in, list(comp_gen_c_module)::in,
 	list(comp_gen_c_data)::in, list(comp_gen_c_var)::in,
@@ -535,8 +532,7 @@
 	MustInit = (pred(Module::in) is semidet :-
 		module_defines_label_with_layout(Module, StackLayoutLabels)
 	),
-	list__filter(MustInit, Modules,
-		AlwaysInitModules, MaybeInitModules),
+    list__filter(MustInit, Modules, AlwaysInitModules, MaybeInitModules),
 	list__chunk(AlwaysInitModules, 40, AlwaysInitModuleBunches),
 	list__chunk(MaybeInitModules, 40, MaybeInitModuleBunches),
 	globals__io_lookup_bool_option(split_c_files, SplitFiles, !IO),
@@ -778,6 +774,7 @@
 
 	% Output declarations for each module layout defined in this module
 	% (there should only be one, of course).
+    %
 :- pred output_debugger_init_list_decls(list(comp_gen_c_data)::in,
 	decl_set::in, decl_set::out, io::di, io::uo) is det.
 
@@ -797,7 +794,7 @@
 	% Output calls to MR_register_module_layout()
 	% for each module layout defined in this module
 	% (there should only be one, of course).
-
+    %
 :- pred output_debugger_init_list(list(comp_gen_c_data)::in, io::di, io::uo)
 	is det.
 
@@ -807,9 +804,7 @@
 		Data = layout_data(LayoutData),
 		LayoutData = module_layout_data(ModuleName, _,_,_,_,_,_,_)
 	->
-		io__write_string(
-			"\tif (MR_register_module_layout != NULL) {\n",
-			!IO),
+        io__write_string("\tif (MR_register_module_layout != NULL) {\n", !IO),
 		io__write_string("\t\t(*MR_register_module_layout)(", !IO),
 		io__write_string("\n\t\t\t&", !IO),
 		output_layout_name(module_layout(ModuleName), !IO),
@@ -850,14 +845,10 @@
 		Kind = proc_layout_proc_id(UserOrUCI),
 		(
 			UserOrUCI = user,
-			io__write_string(
-				"\tMR_write_out_user_proc_static(fp,\n\t\t&",
-				!IO)
+            io__write_string("\tMR_write_out_user_proc_static(fp,\n\t\t&", !IO)
 		;
 			UserOrUCI = uci,
-			io__write_string(
-				"\tMR_write_out_uci_proc_static(fp,\n\t\t&",
-				!IO)
+            io__write_string("\tMR_write_out_uci_proc_static(fp,\n\t\t&", !IO)
 		),
 		output_layout_name(proc_layout(RttiProcLabel, Kind), !IO),
 		io__write_string(");\n", !IO)
@@ -968,8 +959,7 @@
 	;
 		Aditi = no
 	),
-	list__foldl(output_required_user_init_comment, UserInitPredCNames,
-		!IO),
+    list__foldl(output_required_user_init_comment, UserInitPredCNames, !IO),
 	io__write_string("ENDINIT\n", !IO),
 	io__write_string("*/\n\n", !IO).
 
@@ -1036,8 +1026,7 @@
 	( decl_set_is_member(TypeDeclId, !.DeclSet) ->
 		true
 	;
-		output_const_term_type(TypeAndValue, ModuleName,
-			"", "", 0, _, !IO),
+        output_const_term_type(TypeAndValue, ModuleName, "", "", 0, _, !IO),
 		io__write_string("\n", !IO),
 		decl_set_insert(TypeDeclId, !DeclSet)
 	),
@@ -1046,8 +1035,7 @@
 		% There should be a macro MR_DEF_COMMON<n> for every n up to
 		% ChunkSize.
 		ChunkSize = 10,
-		list__chunk(list__reverse(CommonDatas), ChunkSize,
-			CommonDataChunks),
+        list__chunk(list__reverse(CommonDatas), ChunkSize, CommonDataChunks),
 		list__foldl2(output_common_decl_shorthand_chunk(TypeNum),
 			CommonDataChunks, !DeclSet, !IO)
 	;
@@ -1058,8 +1046,7 @@
 		ChunkSize = 20,
 		% The process of creating the multi_map reverses the order of
 		% CommonDatas, we now undo this reversal.
-		list__chunk(list__reverse(CommonDatas), ChunkSize,
-			CommonDataChunks),
+        list__chunk(list__reverse(CommonDatas), ChunkSize, CommonDataChunks),
 		list__foldl2(output_common_decl_chunk(ModuleName, TypeNum),
 			CommonDataChunks, !DeclSet, !IO)
 	).
@@ -1092,8 +1079,7 @@
 	(
 		CommonDatas = [_ | _],
 		io__write_string(",", !IO),
-		output_common_decl_shorthand_chunk_entries(CommonDatas,
-			!DeclSet, !IO)
+        output_common_decl_shorthand_chunk_entries(CommonDatas, !DeclSet, !IO)
 	;
 		CommonDatas = []
 	).
@@ -1129,13 +1115,11 @@
 		io__write_string(";\n", !IO)
 	).
 
-	%
 	% output_c_data_type_def outputs the given the type definition.
 	% This is needed because some compilers need the type definition
 	% to appear before any use of the type in forward declarations
 	% of static constants.
 	%
-
 :- pred output_c_data_type_def(comp_gen_c_data::in,
 	decl_set::in, decl_set::out, io::di, io::uo) is det.
 
@@ -1153,11 +1137,10 @@
 		!DeclSet, !IO) :-
 	io__write_string("\n", !IO),
 
-		% The code for data local to a Mercury module
-		% should normally be visible only within the C file
-		% generated for that module. However, if we generate
-		% multiple C files, the code in each C file must be
-		% visible to the other C files for that Mercury module.
+    % The code for data local to a Mercury module should normally be visible
+    % only within the C file generated for that module. However, if we generate
+    % multiple C files, the code in each C file must be visible to the other
+    % C files for that Mercury module.
 	globals__io_lookup_bool_option(split_c_files, SplitFiles, !IO),
 	ExportedFromFile = SplitFiles,
 	TypeNum = common_cell_get_type_num(TypeAndValue),
@@ -1181,8 +1164,7 @@
 	is det.
 
 output_comp_gen_c_module(StackLayoutLabels,
-		comp_gen_c_module(ModuleName, Procedures),
-		!DeclSet, !IO) :-
+        comp_gen_c_module(ModuleName, Procedures), !DeclSet, !IO) :-
 	io__write_string("\n", !IO),
 	list__foldl2(output_c_procedure_decls(StackLayoutLabels),
 		Procedures, !DeclSet, !IO),
@@ -1230,11 +1212,10 @@
 	Args = common_cell_get_rvals(TypeAndValue),
 	output_rvals_decls(Args, !DeclSet, !IO),
 
-		% The code for data local to a Mercury module
-		% should normally be visible only within the C file
-		% generated for that module. However, if we generate
-		% multiple C files, the code in each C file must be
-		% visible to the other C files for that Mercury module.
+    % The code for data local to a Mercury module should normally be visible
+    % only within the C file generated for that module. However, if we generate
+    % multiple C files, the code in each C file must be visible to the other
+    % C files for that Mercury module.
 	globals__io_lookup_bool_option(split_c_files, SplitFiles, !IO),
 	ExportedFromFile = SplitFiles,
 
@@ -1250,14 +1231,14 @@
 output_user_foreign_code(user_foreign_code(Lang, Foreign_Code, Context),
 		!IO) :-
 	( Lang = c ->
-		globals__io_lookup_bool_option(auto_comments, PrintComments,
-			!IO),
-		( PrintComments = yes ->
+        globals__io_lookup_bool_option(auto_comments, PrintComments, !IO),
+        (
+            PrintComments = yes,
 			io__write_string("/* ", !IO),
 			prog_out__write_context(Context, !IO),
 			io__write_string(" pragma foreign_code */\n", !IO)
 		;
-			true
+            PrintComments = no
 		),
 		output_set_line_num(Context, !IO),
 		io__write_string(Foreign_Code, !IO),
@@ -1280,8 +1261,7 @@
 output_foreign_header_include_line(Decl, !IO) :-
 	Decl = foreign_decl_code(Lang, _IsLocal, Code, Context),
 	( Lang = c ->
-		globals__io_lookup_bool_option(auto_comments, PrintComments,
-			!IO),
+        globals__io_lookup_bool_option(auto_comments, PrintComments, !IO),
 		(
 			PrintComments = yes,
 			io__write_string("/* ", !IO),
@@ -1337,17 +1317,13 @@
 					LabelVars),
 				LabelVars = label_has_var_info
 			->
-				multi_map__set(!.DeclLLMap, ProcLabel,
-					LabelNum, !:DeclLLMap)
+                svmulti_map__set(ProcLabel, LabelNum, !DeclLLMap)
 			;
-				multi_map__set(!.OtherLocalMap, ProcLabel,
-					LabelNum, !:OtherLocalMap),
-				!:RevAddrsToDecl = [DataAddr
-					| !.RevAddrsToDecl]
+                svmulti_map__set(ProcLabel, LabelNum, !OtherLocalMap),
+                !:RevAddrsToDecl = [DataAddr | !.RevAddrsToDecl]
 			)
 		;
-			multi_map__set(!.OtherLocalMap, ProcLabel, LabelNum,
-				!:OtherLocalMap)
+            svmulti_map__set(ProcLabel, LabelNum, !OtherLocalMap)
 		)
 	;
 		Label = entry(_, _),
@@ -1435,8 +1411,7 @@
 		(
 			Label = internal(LabelNum, ProcLabel),
 			DataAddr = layout_addr(LayoutName),
-			LayoutName = label_layout(ProcLabel, LabelNum,
-				LabelVars)
+            LayoutName = label_layout(ProcLabel, LabelNum, LabelVars)
 		->
 			(
 				LabelVars = label_has_var_info,
@@ -1477,8 +1452,7 @@
 			% generated for that module. However, if we generate
 			% multiple C files, the code in each C file must be
 			% visible to the other C files for that Mercury module.
-			globals__io_lookup_bool_option(split_c_files,
-				SplitFiles, !IO),
+            globals__io_lookup_bool_option(split_c_files, SplitFiles, !IO),
 			( SplitFiles = no ->
 				DeclMacro = "MR_decl_static("
 			;
@@ -1530,11 +1504,9 @@
 	(
 		Label = internal(LabelNum, ProcLabel),
 		( map__search(StackLayoutLabels, Label, _DataAddr) ->
-			multi_map__set(!.LayoutMap, ProcLabel, LabelNum,
-				!:LayoutMap)
+            svmulti_map__set(ProcLabel, LabelNum, !LayoutMap)
 		;
-			multi_map__set(!.NoLayoutMap, ProcLabel, LabelNum,
-				!:NoLayoutMap)
+            svmulti_map__set(ProcLabel, LabelNum, !NoLayoutMap)
 		)
 	;
 		Label = entry(_, _),
@@ -1607,12 +1579,13 @@
 	io__write_string(SuffixOpen, !IO),
 	output_proc_label(ProcLabel, no, !IO),
 	io__write_string(");\n", !IO),
-	( InitProcLayout = yes ->
+    (
+        InitProcLayout = yes,
 		io__write_string("\tMR_INIT_PROC_LAYOUT_ADDR(", !IO),
 		output_label(Label, !IO),
 		io__write_string(");\n", !IO)
 	;
-		true
+        InitProcLayout = no
 	).
 
 :- pred label_is_proc_entry(label::in, bool::out) is det.
@@ -1634,13 +1607,12 @@
 output_c_procedure(PrintComments, EmitCLoops, Proc, !IO) :-
 	Proc = c_procedure(Name, Arity, proc(_, ProcId), Instrs, _, _, _),
 	proc_id_to_int(ProcId, ModeNum),
-	( PrintComments = yes ->
-		io__write_string("\n/*-------------------------------------",
-			!IO),
-		io__write_string("------------------------------------*/\n",
-			!IO)
+    (
+        PrintComments = yes,
+        io__write_string("\n/*-------------------------------------", !IO),
+        io__write_string("------------------------------------*/\n", !IO)
 	;
-		true
+        PrintComments = no
 	),
 	(
 		PrintComments = yes,
@@ -1659,19 +1631,19 @@
 
 	llds_out__find_caller_label(Instrs, CallerLabel),
 	llds_out__find_cont_labels(Instrs, bintree_set__init, ContLabelSet),
-	( EmitCLoops = yes ->
-		llds_out__find_while_labels(Instrs,
-			bintree_set__init, WhileSet)
+    (
+        EmitCLoops = yes,
+        llds_out__find_while_labels(Instrs, bintree_set__init, WhileSet)
 	;
+        EmitCLoops = no,
 		WhileSet = bintree_set__init
 	),
 	output_instruction_list(Instrs, PrintComments,
 		CallerLabel - ContLabelSet, WhileSet, !IO).
 
-	% Find the entry label for the procedure,
-	% for use as the profiling "caller label"
-	% field in calls within this procedure.
-
+    % Find the entry label for the procedure, for use as the profiling
+    % "caller label" field in calls within this procedure.
+    %
 :- pred llds_out__find_caller_label(list(instruction)::in, label::out) is det.
 
 llds_out__find_caller_label([], _) :-
@@ -1691,7 +1663,7 @@
 
 	% Locate all the labels which are the continuation labels for calls,
 	% nondet disjunctions, forks or joins, and store them in ContLabelSet.
-
+    %
 :- pred llds_out__find_cont_labels(list(instruction)::in,
 	bintree_set(label)::in, bintree_set(label)::out) is det.
 
@@ -1741,7 +1713,7 @@
 	% L2:				L2:
 	%
 	% The second of these is better if we don't have fast jumps.
-
+    %
 :- pred llds_out__find_while_labels(list(instruction)::in,
 	bintree_set(label)::in, bintree_set(label)::out) is det.
 
@@ -1759,8 +1731,7 @@
 	).
 
 :- pred llds_out__is_while_label(label::in,
-	list(instruction)::in, list(instruction)::out, int::in, int::out)
-	is det.
+    list(instruction)::in, list(instruction)::out, int::in, int::out) is det.
 
 llds_out__is_while_label(_, [], [], !Count).
 llds_out__is_while_label(Label, [Instr0 - Comment0 | Instrs0], Instrs,
@@ -1797,8 +1768,7 @@
 output_instr_decls(_, assign(Lval, Rval), !DeclSet, !IO) :-
 	output_lval_decls(Lval, !DeclSet, !IO),
 	output_rval_decls(Rval, !DeclSet, !IO).
-output_instr_decls(_, call(Target, ContLabel, _, _, _, _),
-		!DeclSet, !IO) :-
+output_instr_decls(_, call(Target, ContLabel, _, _, _, _), !DeclSet, !IO) :-
 	output_code_addr_decls(Target, !DeclSet, !IO),
 	output_code_addr_decls(ContLabel, !DeclSet, !IO).
 output_instr_decls(_, c_code(_, _), !DeclSet, !IO).
@@ -1809,12 +1779,8 @@
 		Struct = pragma_c_struct(StructName, StructFields,
 			MaybeStructFieldsContext)
 	->
-		(
-			decl_set_is_member(pragma_c_struct(StructName),
-				!.DeclSet)
-		->
-			string__append_list(["struct ", StructName,
-				" has been declared already"], Msg),
+        ( decl_set_is_member(pragma_c_struct(StructName), !.DeclSet) ->
+            Msg = "struct " ++ StructName ++ " has been declared already",
 			error(Msg)
 		;
 			true
@@ -1872,19 +1838,20 @@
 output_instr_decls(_, incr_sp(_, _), !DeclSet, !IO).
 output_instr_decls(_, decr_sp(_), !DeclSet, !IO).
 output_instr_decls(StackLayoutLabels, pragma_c(_, Comps, _, _,
-		MaybeLayoutLabel, MaybeOnlyLayoutLabel, _, _, _),
-		!DeclSet, !IO) :-
-	( MaybeLayoutLabel = yes(Label) ->
+        MaybeLayoutLabel, MaybeOnlyLayoutLabel, _, _, _), !DeclSet, !IO) :-
+    (
+        MaybeLayoutLabel = yes(Label),
 		map__lookup(StackLayoutLabels, Label, DataAddr),
 		output_stack_layout_decl(DataAddr, !DeclSet, !IO)
 	;
-		true
+        MaybeLayoutLabel = no
 	),
-	( MaybeOnlyLayoutLabel = yes(OnlyLabel) ->
+    (
+        MaybeOnlyLayoutLabel = yes(OnlyLabel),
 		map__lookup(StackLayoutLabels, OnlyLabel, OnlyDataAddr),
 		output_stack_layout_decl(OnlyDataAddr, !DeclSet, !IO)
 	;
-		true
+        MaybeOnlyLayoutLabel = no
 	),
 	list__foldl2(output_pragma_c_component_decls, Comps, !DeclSet, !IO).
 output_instr_decls(_, init_sync_term(Lval, _), !DeclSet, !IO) :-
@@ -1919,8 +1886,8 @@
 output_instruction_list([], _, _, _, !IO).
 output_instruction_list([Instr0 - Comment0 | Instrs], PrintComments, ProfInfo,
 		WhileSet, !IO) :-
-	output_instruction_and_comment(Instr0, Comment0,
-		PrintComments, ProfInfo, !IO),
+    output_instruction_and_comment(Instr0, Comment0, PrintComments, ProfInfo,
+        !IO),
 	(
 		Instr0 = label(Label),
 		bintree_set__is_member(Label, WhileSet)
@@ -1947,8 +1914,7 @@
 			PrintComments, ProfInfo, WhileSet, !IO)
 	; Instr0 = goto(label(Label)) ->
 		io__write_string("\t/* continue */ } /* end while */\n", !IO),
-		output_instruction_list(Instrs, PrintComments, ProfInfo,
-			WhileSet, !IO)
+        output_instruction_list(Instrs, PrintComments, ProfInfo, WhileSet, !IO)
 	; Instr0 = if_val(Rval, label(Label)) ->
 		io__write_string("\tif (", !IO),
 		output_test_rval(Rval, !IO),
@@ -1999,10 +1965,10 @@
 		)
 	).
 
-	% output_instruction_and_comment/5 is only for debugging.
+    % output_debug_instruction_and_comment/5 is only for debugging.
 	% Normally we use output_instruction_and_comment/6.
-
-output_instruction_and_comment(Instr, Comment, PrintComments, !IO) :-
+    %
+output_debug_instruction_and_comment(Instr, Comment, PrintComments, !IO) :-
 	bintree_set__init(ContLabelSet),
 	DummyModule = unqualified("DEBUG"),
 	DummyPredName = "DEBUG",
@@ -2013,10 +1979,10 @@
 	output_instruction_and_comment(Instr, Comment, PrintComments,
 		ProfInfo, !IO).
 
-	% output_instruction/3 is only for debugging.
+    % output_debug_instruction/3 is only for debugging.
 	% Normally we use output_instruction/4.
-
-output_instruction(Instr, !IO) :-
+    %
+output_debug_instruction(Instr, !IO) :-
 	bintree_set__init(ContLabelSet),
 	DummyModule = unqualified("DEBUG"),
 	DummyPredName = "DEBUG",
@@ -2066,7 +2032,8 @@
 	output_rval_as_type(Rval, Type, !IO),
 	io__write_string(";\n", !IO).
 
-output_instruction(call(Target, ContLabel, LiveVals, _, _, _), ProfInfo,			!IO) :-
+output_instruction(call(Target, ContLabel, LiveVals, _, _, _), ProfInfo,
+        !IO) :-
 	ProfInfo = CallerLabel - _,
 	output_call(Target, ContLabel, CallerLabel, !IO),
 	output_gc_livevals(LiveVals, !IO).
@@ -2093,9 +2060,7 @@
 				io__write_string(");\n", !IO)
 			;
 				MaybeFailCont = no,
-				io__write_string(
-					"\tMR_mkpragmaframe_no_redoip(""",
-					!IO),
+                io__write_string("\tMR_mkpragmaframe_no_redoip(""", !IO),
 				c_util__output_quoted_string(Msg, !IO),
 				io__write_string(""", ", !IO),
 				io__write_int(Num, !IO),
@@ -2223,8 +2188,7 @@
 			MaybeTag = yes(Tag),
 			(
 				MaybeOffset = yes(_),
-				io__write_string("\tMR_tag_offset_incr_hp(",
-					!IO),
+                io__write_string("\tMR_tag_offset_incr_hp(", !IO),
 				output_lval_as_word(Lval, !IO),
 				io__write_string(", ", !IO),
 				output_tag(Tag, !IO)
@@ -2372,14 +2336,14 @@
 output_pragma_c_component(pragma_c_raw_code(C_Code, _), !IO) :-
 	io__write_string(C_Code, !IO).
 output_pragma_c_component(pragma_c_fail_to(Label), !IO) :-
-	io__write_string("if (!" ++ pragma_succ_ind_name ++
-		") MR_GOTO_LAB(", !IO),
+    io__write_string("if (!" ++ pragma_succ_ind_name ++ ") MR_GOTO_LAB(", !IO),
 	output_label(Label, no, !IO),
 	io__write_string(");\n", !IO).
 output_pragma_c_component(pragma_c_noop, !IO).
 
 	% Output the local variable declarations at the top of the
 	% pragma_foreign code for C.
+    %
 :- pred output_pragma_decls(list(pragma_c_decl)::in, io::di, io::uo) is det.
 
 output_pragma_decls([], !IO).
@@ -2402,7 +2366,8 @@
 	),
 	output_pragma_decls(Decls, !IO).
 
-	% Output declarations for any rvals used to initialize the inputs
+    % Output declarations for any rvals used to initialize the inputs.
+    %
 :- pred output_pragma_input_rval_decls(list(pragma_c_input)::in,
 	decl_set::in, decl_set::out, io::di, io::uo) is det.
 
@@ -2414,6 +2379,7 @@
 
 	% Output the input variable assignments at the top of the
 	% pragma foreign_code code for C.
+    %
 :- pred output_pragma_inputs(list(pragma_c_input)::in, io::di, io::uo) is det.
 
 output_pragma_inputs([], !IO).
@@ -2427,8 +2393,9 @@
 	),
 	output_pragma_inputs(Inputs, !IO).
 
-	% Output the input variable assignments at the top of the
+    % Output an input variable assignment at the top of the
 	% pragma foreign_code code for C.
+    %
 :- pred output_pragma_input(pragma_c_input::in, io::di, io::uo) is det.
 
 output_pragma_input(Input, !IO) :-
@@ -2437,8 +2404,7 @@
 	io__write_string("\t", !IO),
 	(
 		MaybeForeignTypeInfo = yes(ForeignTypeInfo),
-		ForeignTypeInfo = pragma_c_foreign_type(ForeignType,
-			Assertions),
+        ForeignTypeInfo = pragma_c_foreign_type(ForeignType, Assertions),
 		% For foreign types for which c_type_is_word_sized_int_or_ptr
 		% succeeds, the code in the else branch is not only correct,
 		% it also generates faster code than would be generated by
@@ -2479,7 +2445,8 @@
 	),
 	io__write_string(";\n", !IO).
 
-	% Output declarations for any lvals used for the outputs
+    % Output declarations for any lvals used for the outputs.
+    %
 :- pred output_pragma_output_lval_decls(list(pragma_c_output)::in,
 	decl_set::in, decl_set::out, io::di, io::uo) is det.
 
@@ -2490,7 +2457,8 @@
 	output_pragma_output_lval_decls(Outputs, !DeclSet, !IO).
 
 	% Output the output variable assignments at the bottom of the
-	% pragma foreign code for C
+    % pragma foreign code for C.
+    %
 :- pred output_pragma_outputs(list(pragma_c_output)::in, io::di, io::uo)
 	is det.
 
@@ -2505,8 +2473,9 @@
 	),
 	output_pragma_outputs(Outputs, !IO).
 
-	% Output the output variable assignments at the bottom of the
-	% pragma foreign code for C
+    % Output a output variable assignment at the bottom of the
+    % pragma foreign code for C.
+    %
 :- pred output_pragma_output(pragma_c_output::in, io::di, io::uo) is det.
 
 output_pragma_output(Output, !IO) :-
@@ -2515,8 +2484,7 @@
 	io__write_string("\t", !IO),
 	(
 		MaybeForeignType = yes(ForeignTypeInfo),
-		ForeignTypeInfo = pragma_c_foreign_type(ForeignType,
-			Assertions),
+        ForeignTypeInfo = pragma_c_foreign_type(ForeignType, Assertions),
 		( list__member(can_pass_as_mercury_type, Assertions) ->
 			output_lval_as_word(Lval, !IO),
 			io__write_string(" = ", !IO),
@@ -2624,9 +2592,10 @@
 output_layout_locns([], !IO).
 output_layout_locns([Locn | Locns], !IO) :-
 	output_layout_locn(Locn, !IO),
-	( Locns = [] ->
-		true
+    (
+        Locns = []
 	;
+        Locns = [_ | _],
 		io__write_string(" and ", !IO),
 		output_layout_locns(Locns, !IO)
 	).
@@ -2714,7 +2683,7 @@
 	output_rval_decls(Lval, "", "", 0, _, !DeclSet, !IO).
 
 	% output_rval_decls(Rval, FirstIndent, LaterIndent, N0, N,
-	% DeclSet0, DeclSet) outputs the declarations of any static constants,
+    % !DeclSet) outputs the declarations of any static constants,
 	% etc. that need to be declared before output_rval(Rval) is called.
 	% FirstIndent is output before the first declaration, while
 	% LaterIndent is output before all later declaration; N0 and N
@@ -2723,7 +2692,7 @@
 	% Every time we emit a declaration for a symbol, we insert it into the
 	% set of symbols we've already declared. That way, we avoid generating
 	% the same symbol twice, which would cause an error in the C code.
-
+    %
 :- pred output_rval_decls(rval::in, string::in, string::in, int::in, int::out,
 	decl_set::in, decl_set::out, io::di, io::uo) is det.
 
@@ -2743,15 +2712,13 @@
 			!N, !DeclSet, !IO)
 	; Const = float_const(FloatVal) ->
 		%
-		% If floats are boxed, and the static ground terms
-		% option is enabled, then for each float constant
-		% which we might want to box we declare a static const
-		% variable holding that constant.
-		%
-		globals__io_lookup_bool_option(unboxed_float,
-			UnboxedFloat, !IO),
-		globals__io_lookup_bool_option(static_ground_terms,
-			StaticGroundTerms, !IO),
+        % If floats are boxed, and the static ground terms option is enabled,
+        % then for each float constant which we might want to box we declare
+        % a static const variable holding that constant.
+        %
+        globals__io_lookup_bool_option(unboxed_float, UnboxedFloat, !IO),
+        globals__io_lookup_bool_option(static_ground_terms, StaticGroundTerms,
+            !IO),
 		(
 			UnboxedFloat = no,
 			StaticGroundTerms = yes
@@ -2762,15 +2729,12 @@
 				true
 			;
 				decl_set_insert(FloatLabel, !DeclSet),
-				FloatString = c_util__make_float_literal(
-					FloatVal),
-				output_indent(FirstIndent, LaterIndent,
-					!.N, !IO),
+                FloatString = c_util__make_float_literal( FloatVal),
+                output_indent(FirstIndent, LaterIndent, !.N, !IO),
 				!:N = !.N + 1,
-				io__write_strings([
-					"static const MR_Float ",
-					"mercury_float_const_", FloatName,
-					" = ", FloatString, ";\n"
+                io__write_strings(["static const MR_Float ",
+                    "mercury_float_const_", FloatName, " = ", FloatString,
+                    ";\n"
 				], !IO)
 			)
 		;
@@ -2787,42 +2751,35 @@
 	output_rval_decls(Rval1, FirstIndent, LaterIndent, !N, !DeclSet, !IO),
 	output_rval_decls(Rval2, FirstIndent, LaterIndent, !N, !DeclSet, !IO),
 		%
-		% If floats are boxed, and the static ground terms
-		% option is enabled, then for each float constant
-		% which we might want to box we declare a static const
-		% variable holding that constant.
+        % If floats are boxed, and the static ground terms option is enabled,
+        % then for each float constant which we might want to box we declare
+        % a static const variable holding that constant.
 		%
 	( c_util__float_op(Op, OpStr) ->
 		globals__io_lookup_bool_option(unboxed_float, UnboxFloat, !IO),
-		globals__io_lookup_bool_option(static_ground_terms,
-			StaticGroundTerms, !IO),
+        globals__io_lookup_bool_option(static_ground_terms, StaticGroundTerms,
+            !IO),
 		(
 			UnboxFloat = no,
 			StaticGroundTerms = yes,
-			llds_out__float_const_binop_expr_name(Op, Rval1, Rval2,
-				FloatName)
+            llds_out__float_const_binop_expr_name(Op, Rval1, Rval2, FloatName)
 		->
 			FloatLabel = float_label(FloatName),
 			( decl_set_is_member(FloatLabel, !.DeclSet) ->
 				true
 			;
 				decl_set_insert(FloatLabel, !DeclSet),
-				output_indent(FirstIndent, LaterIndent, !.N,
-					!IO),
+                output_indent(FirstIndent, LaterIndent, !.N, !IO),
 				!:N = !.N + 1,
 				io__write_string("static const ", !IO),
 				output_llds_type(float, !IO),
 				io__write_string(" mercury_float_const_", !IO),
 				io__write_string(FloatName, !IO),
 				io__write_string(" = ", !IO),
-					% note that we just output the
-					% expression here, and let the C
-					% compiler evaluate it, rather than
-					% evaluating it ourselves;
-					% this avoids having to deal with some
-					% nasty issues regarding floating point
-					% accuracy when doing
-					% cross-compilation.
+                % Note that we just output the expression here, and let the C
+                % compiler evaluate it, rather than evaluating it ourselves.
+                % This avoids having to deal with some nasty issues regarding
+                % floating point accuracy when doing cross-compilation.
 				output_rval_as_type(Rval1, float, !IO),
 				io__write_string(" ", !IO),
 				io__write_string(OpStr, !IO),
@@ -2838,8 +2795,7 @@
 	).
 output_rval_decls(mem_addr(MemRef), FirstIndent, LaterIndent,
 		!N, !DeclSet, !IO) :-
-	output_mem_ref_decls(MemRef, FirstIndent, LaterIndent,
-		!N, !DeclSet, !IO).
+    output_mem_ref_decls(MemRef, FirstIndent, LaterIndent, !N, !DeclSet, !IO).
 
 :- pred output_rvals_decls(list(rval)::in, decl_set::in, decl_set::out,
 	io::di, io::uo) is det.
@@ -2866,16 +2822,16 @@
 	output_rval_decls(Rval, FirstIndent, LaterIndent, !N, !DeclSet, !IO).
 
 %-----------------------------------------------------------------------------%
-
+%
 % The following predicates are used to compute the names used for
 % floating point static constants.
 
+    % Given an rval, succeed iff it is a floating point constant expression;
+    % if so, return a name for that rval that is suitable for use in a C
+    % identifier. Different rvals must be given different names.
+    %
 :- pred llds_out__float_const_expr_name(rval::in, string::out) is semidet.
 
-% Given an rval, succeed iff it is a floating point constant expression;
-% if so, return a name for that rval that is suitable for use in a C
-% identifier. Different rvals must be given different names.
-
 llds_out__float_const_expr_name(Expr, Name) :-
 	( Expr = const(float_const(Float)) ->
 		llds_out__float_literal_name(Float, Name)
@@ -2885,46 +2841,41 @@
 		fail
 	).
 
+    % Given a binop rval, succeed iff that rval is a floating point constant
+    % expression; if so, return a name for that rval that is suitable for use
+    % in a C identifier.  Different rvals must be given different names.
+    %
 :- pred llds_out__float_const_binop_expr_name(binary_op::in, rval::in, rval::in,
 	string::out) is semidet.
 
-% Given a binop rval, succeed iff that rval is a floating point constant
-% expression; if so, return a name for that rval that is suitable for use in
-% a C identifier.  Different rvals must be given different names.
-
 llds_out__float_const_binop_expr_name(Op, Arg1, Arg2, Name) :-
 	llds_out__float_op_name(Op, OpName),
 	llds_out__float_const_expr_name(Arg1, Arg1Name),
 	llds_out__float_const_expr_name(Arg2, Arg2Name),
-	% we use prefix notation (operator, argument, argument)
-	% rather than infix, to ensure that different rvals get
-	% different names
-	string__append_list([OpName, "_", Arg1Name, "_", Arg2Name],
-		Name).
-
+    % We use prefix notation (operator, argument, argument) rather than infix,
+    % to ensure that different rvals get different names.
+    Name = OpName ++ "_" ++ Arg1Name ++ "_" ++ Arg2Name.
+
+    % Given an rval which is a floating point literal, return
+    % a name for that rval that is suitable for use in a C identifier.
+    % Different rvals must be given different names.
+    %
 :- pred llds_out__float_literal_name(float::in, string::out) is det.
 
-% Given an rval which is a floating point literal, return
-% a name for that rval that is suitable for use in a C identifier.
-% Different rvals must be given different names.
-
 llds_out__float_literal_name(Float, FloatName) :-
-	%
-	% The name of the variable is based on the
-	% value of the float const, with "pt" instead
-	% of ".", "plus" instead of "+", and "neg" instead of "-".
-	%
+    % The name of the variable is based on the value of the float const, with
+    % "pt" instead of ".", "plus" instead of "+", and "neg" instead of "-".
 	FloatName0 = c_util__make_float_literal(Float),
 	string__replace_all(FloatName0, ".", "pt", FloatName1),
 	string__replace_all(FloatName1, "+", "plus", FloatName2),
 	string__replace_all(FloatName2, "-", "neg", FloatName).
 
+    % Succeed iff the binary operator is an operator whose return
+    % type is float; bind the output string to a name for that operator
+    % that is suitable for use in a C identifier
+    %
 :- pred llds_out__float_op_name(binary_op::in, string::out) is semidet.
 
-% succeed iff the binary operator is an operator whose return
-% type is float; bind the output string to a name for that operator
-% that is suitable for use in a C identifier
-
 llds_out__float_op_name(float_plus, "plus").
 llds_out__float_op_name(float_minus, "minus").
 llds_out__float_op_name(float_times, "times").
@@ -2981,7 +2932,7 @@
 	%
 	% output_const_term_type outputs the first part above. The second
 	% and third parts are output by output_const_term_decl_or_defn.
-
+    %
 :- pred output_const_term_type(common_cell_type_and_value::in, module_name::in,
 	string::in, string::in, int::in, int::out, io::di, io::uo) is det.
 
@@ -3046,7 +2997,7 @@
 	% code addresses the earlier passes will have replaced any code
 	% addresses with dummy values that will have to be overridden with
 	% the real code address at initialization time.
-
+    %
 :- func data_addr_may_include_non_static_code_address(data_addr) = bool.
 
 data_addr_may_include_non_static_code_address(data_addr(_, DataName)) =
@@ -3115,12 +3066,11 @@
 	),
 	output_cons_arg_group_types(Groups, Indent, ArgNum + 1, !IO).
 
-	% Given an rval, figure out the type it would have as
-	% an argument.  Normally that's the same as its usual type;
-	% the exception is that for boxed floats, the type is data_ptr
-	% (i.e. the type of the boxed value) rather than float
-	% (the type of the unboxed value).
-
+    % Given an rval, figure out the type it would have as an argument.
+    % Normally that's the same as its usual type; the exception is that
+    % for boxed floats, the type is data_ptr (i.e. the type of the boxed value)
+    % rather than float (the type of the unboxed value).
+    %
 :- pred llds_out__rval_type_as_arg(rval::in, llds_type::out, io::di, io::uo)
 	is det.
 
@@ -3136,8 +3086,8 @@
 		ArgType = Type
 	).
 
-	% Same as output_llds_type, but will put parentheses
-	% around the llds_type.
+    % Same as output_llds_type, but will put parentheses around the llds_type.
+    %
 :- pred output_llds_type_cast(llds_type::in, io::di, io::uo) is det.
 
 output_llds_type_cast(LLDSType, !IO) :-
@@ -3178,7 +3128,7 @@
 
 	% Output the arguments, each on its own line prefixing with Indent,
 	% and with a cast appropriate to its type if necessary.
-
+    %
 :- pred output_cons_args(assoc_list(rval, llds_type)::in, io::di, io::uo)
 	is det.
 
@@ -3192,10 +3142,12 @@
 	;
 		output_rval_as_type(Rval, Type, !IO)
 	),
-	( RvalsTypes \= [] ->
+    (
+        RvalsTypes = [_ | _],
 		io__write_string(",\n", !IO),
 		output_cons_args(RvalsTypes, !IO)
 	;
+        RvalsTypes = [],
 		io__write_string("\n", !IO)
 	).
 
@@ -3217,8 +3169,7 @@
 				output_cons_arg_group_ints(Ints, !IO)
 			;
 				Check = yes,
-				output_cons_arg_group_ints_check(Ints, Type,
-					!IO)
+                output_cons_arg_group_ints_check(Ints, Type, !IO)
 			)
 		;
 			output_cons_arg_group_elements(Type, Rvals, !IO)
@@ -3235,10 +3186,12 @@
 			output_rval_as_type(Rval, Type, !IO)
 		)
 	),
-	( Groups \= [] ->
+    (
+        Groups = [_ | _],
 		io__write_string(",\n", !IO),
 		output_cons_arg_groups(Groups, !IO)
 	;
+        Groups = [],
 		io__write_string("\n", !IO)
 	).
 
@@ -3248,10 +3201,12 @@
 output_cons_arg_group_elements(_, [], !IO).
 output_cons_arg_group_elements(Type, [Rval | Rvals], !IO) :-
 	output_rval_as_type(Rval, Type, !IO),
-	( Rvals \= [] ->
+    (
+        Rvals = [_ | _],
 		io__write_string(",\n", !IO),
 		output_cons_arg_group_elements(Type, Rvals, !IO)
 	;
+        Rvals = [],
 		io__write_string("\n", !IO)
 	).
 
@@ -3260,10 +3215,12 @@
 output_cons_arg_group_ints([], !IO).
 output_cons_arg_group_ints([Int | Ints], !IO) :-
 	io__write_int(Int, !IO),
-	( Ints \= [] ->
+    (
+        Ints = [_ | _],
 		io__write_string(",\n", !IO),
 		output_cons_arg_group_ints(Ints, !IO)
 	;
+        Ints = [],
 		io__write_string("\n", !IO)
 	).
 
@@ -3273,10 +3230,12 @@
 output_cons_arg_group_ints_check([], _, !IO).
 output_cons_arg_group_ints_check([Int | Ints], Type, !IO) :-
 	output_int_const(Int, Type, !IO),
-	( Ints \= [] ->
+    (
+        Ints = [_ | _],
 		io__write_string(",\n", !IO),
 		output_cons_arg_group_ints_check(Ints, Type, !IO)
 	;
+        Ints = [],
 		io__write_string("\n", !IO)
 	).
 
@@ -3287,7 +3246,7 @@
 :- func check_int_const_sizes = bool.
 :- pragma inline(check_int_const_sizes/0).
 
-% If you this to `yes', we will test all integer constants places into static
+% If you this to `yes', we will test all integer constants placed into static
 % data structures to see if they fit into the space allocated for them.
 
 check_int_const_sizes = no.
@@ -3339,10 +3298,10 @@
 
 %-----------------------------------------------------------------------------%
 
-% output_lval_decls(Lval, ...) outputs the declarations of any
-% static constants, etc. that need to be declared before
-% output_lval(Lval) is called.
-
+    % output_lval_decls(Lval, ...) outputs the declarations of any
+    % static constants, etc. that need to be declared before
+    % output_lval(Lval) is called.
+    %
 :- pred output_lval_decls(lval::in, decl_set::in, decl_set::out,
 	io::di, io::uo) is det.
 
@@ -3355,8 +3314,7 @@
 output_lval_decls(field(_, Rval, FieldNum), FirstIndent, LaterIndent,
 		!N, !DeclSet, !IO) :-
 	output_rval_decls(Rval, FirstIndent, LaterIndent, !N, !DeclSet, !IO),
-	output_rval_decls(FieldNum, FirstIndent, LaterIndent,
-		!N, !DeclSet, !IO).
+    output_rval_decls(FieldNum, FirstIndent, LaterIndent, !N, !DeclSet, !IO).
 output_lval_decls(reg(_, _), _, _, !N, !DeclSet, !IO).
 output_lval_decls(stackvar(_), _, _, !N, !DeclSet, !IO).
 output_lval_decls(framevar(_), _, _, !N, !DeclSet, !IO).
@@ -3394,12 +3352,13 @@
 	;
 		decl_set_insert(code_addr(CodeAddress), !DeclSet),
 		need_code_addr_decls(CodeAddress, NeedDecl, !IO),
-		( NeedDecl = yes ->
+        (
+            NeedDecl = yes,
 			output_indent(FirstIndent, LaterIndent, !.N, !IO),
 			!:N = !.N + 1,
 			output_code_addr_decls(CodeAddress, !IO)
 		;
-			true
+            NeedDecl = no
 		)
 	).
 
@@ -3442,8 +3401,8 @@
 	).
 need_code_addr_decls(do_trace_redo_fail_shallow, yes, !IO).
 need_code_addr_decls(do_trace_redo_fail_deep, yes, !IO).
-need_code_addr_decls(do_call_closure, yes, !IO).
-need_code_addr_decls(do_call_class_method, yes, !IO).
+need_code_addr_decls(do_call_closure(_), yes, !IO).
+need_code_addr_decls(do_call_class_method(_), yes, !IO).
 need_code_addr_decls(do_not_reached, yes, !IO).
 
 :- pred output_code_addr_decls(code_addr::in, io::di, io::uo) is det.
@@ -3480,15 +3439,15 @@
 	io__write_string("MR_declare_entry(MR_do_trace_redo_fail_shallow);\n",
 		!IO).
 output_code_addr_decls(do_trace_redo_fail_deep, !IO) :-
-	io__write_string("MR_declare_entry(MR_do_trace_redo_fail_deep);\n",
-		!IO).
-output_code_addr_decls(do_call_closure, !IO) :-
-	io__write_string(
-		"MR_declare_entry(mercury__do_call_closure_compact);\n", !IO).
-output_code_addr_decls(do_call_class_method, !IO) :-
-	io__write_string(
-		"MR_declare_entry(mercury__do_call_class_method_compact);\n",
-		!IO).
+    io__write_string("MR_declare_entry(MR_do_trace_redo_fail_deep);\n", !IO).
+output_code_addr_decls(do_call_closure(Variant), !IO) :-
+    io__write_string("MR_declare_entry(mercury__do_call_closure_", !IO),
+    io__write_string(ho_call_variant_to_string(Variant), !IO),
+    io__write_string(");\n", !IO).
+output_code_addr_decls(do_call_class_method(Variant), !IO) :-
+    io__write_string("MR_declare_entry(mercury__do_call_class_method_", !IO),
+    io__write_string(ho_call_variant_to_string(Variant), !IO),
+    io__write_string(");\n", !IO).
 output_code_addr_decls(do_not_reached, !IO) :-
 	io__write_string("MR_declare_entry(MR_do_not_reached);\n", !IO).
 
@@ -3520,8 +3479,7 @@
 		true
 	;
 		decl_set_insert(data_addr(DataAddr), !DeclSet),
-		output_data_addr_decls_2(DataAddr, FirstIndent, LaterIndent,
-			!N, !IO)
+        output_data_addr_decls_2(DataAddr, FirstIndent, LaterIndent, !N, !IO)
 	).
 
 :- pred output_data_addr_decls_2(data_addr::in, string::in, string::in,
@@ -3557,8 +3515,11 @@
 		= LinkageStr :-
 	globals__lookup_bool_option(Globals, split_c_files, SplitFiles),
 	(
-		( DefaultLinkage = extern
-		; SplitFiles = yes, StaticEvenIfSplit = no
+        (
+            DefaultLinkage = extern
+        ;
+            SplitFiles = yes,
+            StaticEvenIfSplit = no
 		)
 	->
 		(
@@ -3569,12 +3530,10 @@
 			LinkageStr = "extern "
 		)
 	;
-		%
-		% Previously we used to always write `extern' here, but
-		% declaring something `extern' and then later defining it as
-		% `static' causes undefined behavior -- on many systems, it
-		% works, but on some systems such as RS/6000s running AIX
-		% it results in link errors.
+        % Previously we used to always write `extern' here, but declaring
+        % something `extern' and then later defining it as `static' causes
+        % undefined behavior -- on many systems, it works, but on some systems
+        % such as RS/6000s running AIX, it results in link errors.
 		%
 		LinkageStr = "static "
 	).
@@ -3589,12 +3548,11 @@
 		ConstStr = "const "
 	).
 
-	% This predicate outputs the storage class, type and name
-	% of the variable specified by the first two arguments.
-	% The third argument should be true if the variable is being
-	% defined, and false if it is only being declared (since the
-	% storage class "extern" is needed only on declarations).
-
+    % This predicate outputs the storage class, type and name of the variable
+    % specified by the first two arguments. The third argument should be true
+    % if the variable is being defined, and false if it is only being declared
+    % (since the storage class "extern" is needed only on declarations).
+    %
 :- pred output_data_addr_storage_type_name(module_name::in, data_name::in,
 	bool::in, string::in, io::di, io::uo) is det.
 
@@ -3605,8 +3563,7 @@
 	LinkageStr = c_data_linkage_string(Globals, Linkage, no, BeingDefined),
 	io__write_string(LinkageStr, !IO),
 
-	InclCodeAddr = data_name_may_include_non_static_code_address(
-		DataVarName),
+    InclCodeAddr = data_name_may_include_non_static_code_address(DataVarName),
 	c_data_const_string(Globals, InclCodeAddr, ConstStr),
 	io__write_string(ConstStr, !IO),
 
@@ -3646,8 +3603,7 @@
 		bintree_set__is_member(Label, ContLabelSet),
 		ProfileTime = yes
 	->
-		io__write_string("\tMR_update_prof_current_proc(MR_LABEL_AP(",
-			!IO),
+        io__write_string("\tMR_update_prof_current_proc(MR_LABEL_AP(", !IO),
 		output_label(CallerLabel, no, !IO),
 		io__write_string("));\n", !IO)
 	;
@@ -3658,15 +3614,13 @@
 
 :- pred output_goto(code_addr::in, label::in, io::di, io::uo) is det.
 
-	% Note that we do some optimization here:
-	% instead of always outputting `MR_GOTO(<label>)', we
-	% output different things for each different kind of label.
-
+    % Note that we do some optimization here: instead of always outputting
+    % `MR_GOTO(<label>)', we output different things for each different
+    % kind of label.
 output_goto(label(Label), CallerLabel, !IO) :-
 	(
 		Label = entry(exported, _),
-		globals__io_lookup_bool_option(profile_calls, ProfileCalls,
-			!IO),
+        globals__io_lookup_bool_option(profile_calls, ProfileCalls, !IO),
 		(
 			ProfileCalls = yes,
 			io__write_string("MR_tailcall(", !IO),
@@ -3682,8 +3636,7 @@
 		)
 	;
 		Label = entry(local, _),
-		globals__io_lookup_bool_option(profile_calls, ProfileCalls,
-			!IO),
+        globals__io_lookup_bool_option(profile_calls, ProfileCalls, !IO),
 		(
 			ProfileCalls = yes,
 			io__write_string("MR_tailcall(", !IO),
@@ -3699,8 +3652,7 @@
 		)
 	;
 		Label = entry(c_local, _),
-		globals__io_lookup_bool_option(profile_calls, ProfileCalls,
-			!IO),
+        globals__io_lookup_bool_option(profile_calls, ProfileCalls, !IO),
 		(
 			ProfileCalls = yes,
 			io__write_string("MR_localtailcall(", !IO),
@@ -3767,25 +3719,25 @@
 	io__write_string("MR_GOTO(MR_ENTRY(MR_do_trace_redo_fail_shallow));\n",
 		!IO).
 output_goto(do_trace_redo_fail_deep, _, !IO) :-
-	io__write_string("MR_GOTO(MR_ENTRY(MR_do_trace_redo_fail_deep));\n",
-		!IO).
-output_goto(do_call_closure, CallerLabel, !IO) :-
+    io__write_string("MR_GOTO(MR_ENTRY(MR_do_trace_redo_fail_deep));\n", !IO).
+output_goto(do_call_closure(Variant), CallerLabel, !IO) :-
 	% see comment in output_call for why we use `noprof_' etc. here
 	io__write_string("MR_set_prof_ho_caller_proc(", !IO),
 	output_label_as_code_addr(CallerLabel, !IO),
 	io__write_string(");\n\t", !IO),
-	io__write_string("MR_np_tailcall_ent(do_call_closure_compact);\n",
-		!IO).
-output_goto(do_call_class_method, CallerLabel, !IO) :-
+    io__write_string("MR_np_tailcall_ent(do_call_closure_", !IO),
+    io__write_string(ho_call_variant_to_string(Variant), !IO),
+    io__write_string(");\n", !IO).
+output_goto(do_call_class_method(Variant), CallerLabel, !IO) :-
 	% see comment in output_call for why we use `noprof_' etc. here
 	io__write_string("MR_set_prof_ho_caller_proc(", !IO),
 	output_label_as_code_addr(CallerLabel, !IO),
 	io__write_string(");\n\t", !IO),
-	io__write_string("MR_np_tailcall_ent(do_call_class_method_compact);\n",
-		!IO).
+    io__write_string("MR_np_tailcall_ent(do_call_class_method_", !IO),
+    io__write_string(ho_call_variant_to_string(Variant), !IO),
+    io__write_string(");\n", !IO).
 output_goto(do_not_reached, CallerLabel, !IO) :-
-	io__write_string("MR_tailcall(MR_ENTRY(MR_do_not_reached),\n\t\t",
-		!IO),
+    io__write_string("MR_tailcall(MR_ENTRY(MR_do_not_reached),\n\t\t", !IO),
 	output_label_as_code_addr(CallerLabel, !IO),
 	io__write_string(");\n", !IO).
 
@@ -3796,25 +3748,23 @@
 	% We also reduce the size of the output by emitting shorthand forms of
 	% the relevant macros when possible, allowing those shorthand macros
 	% to apply mercury__ prefixes and possible MR_ENTRY() wrappers.
-
+    %
 :- pred output_call(code_addr::in, code_addr::in, label::in, io::di, io::uo)
 	is det.
 
 output_call(Target, Continuation, CallerLabel, !IO) :-
 	io__write_string("\t", !IO),
-	% For profiling, we ignore calls to do_call_closure
-	% and do_call_class_method, because in general they
-	% lead to cycles in the call graph that screw up the
-	% profile.  By generating a `noprof_call' rather than
-	% a `call', we ensure that time spent inside those
-	% routines is credited to the caller, rather than to
-	% do_call_closure or do_call_class_method itself.
-	% But if we do use a noprof_call, we need to set
-	% MR_prof_ho_caller_proc, so that the callee knows
+    % For profiling, we ignore calls to do_call_closure and
+    % do_call_class_method, because in general they lead to cycles in the call
+    % graph that screw up the profile. By generating a `noprof_call' rather
+    % than a `call', we ensure that time spent inside those routines
+    % is credited to the caller, rather than to do_call_closure or
+    % do_call_class_method itself. But if we do use a noprof_call,
+    % we need to set MR_prof_ho_caller_proc, so that the callee knows
 	% which proc it has been called from.
 	(
-		( Target = do_call_closure
-		; Target = do_call_class_method
+        ( Target = do_call_closure(_)
+        ; Target = do_call_class_method(_)
 		)
 	->
 		ProfileCall = no,
@@ -3822,8 +3772,7 @@
 		output_label_as_code_addr(CallerLabel, !IO),
 		io__write_string(");\n\t", !IO)
 	;
-		globals__io_lookup_bool_option(profile_calls, ProfileCall,
-			!IO)
+        globals__io_lookup_bool_option(profile_calls, ProfileCall, !IO)
 	),
 	(
 		Target = label(Label),
@@ -3884,12 +3833,10 @@
 			output_label(ContLabel, !IO)
 		;
 			ProfileCall = no,
-			code_addr_to_string_base(Target, BaseStr,
-				NeedsPrefix, Wrapper),
+            code_addr_to_string_base(Target, BaseStr, NeedsPrefix, Wrapper),
 			(
 				NeedsPrefix = no,
-				io__write_string("MR_noprof_call_localret(",
-					!IO),
+                io__write_string("MR_noprof_call_localret(", !IO),
 				output_code_addr_from_pieces(BaseStr,
 					NeedsPrefix, Wrapper, !IO),
 				io__write_string(",\n\t\t", !IO),
@@ -3897,24 +3844,21 @@
 			;
 				NeedsPrefix = yes,
 				Wrapper = entry,
-				io__write_string("MR_np_call_localret_ent(",
-					!IO),
+                io__write_string("MR_np_call_localret_ent(", !IO),
 				io__write_string(BaseStr, !IO),
 				io__write_string(",\n\t\t", !IO),
 				output_label(ContLabel, no, !IO)
 			;
 				NeedsPrefix = yes,
 				Wrapper = label,
-				% We should never get here; the conditions
-				% that lead here in this switch should have
-				% been caught by the first if-then-else
-				% condition that tests Target.
+                % We should never get here; the conditions that lead here
+                % in this switch should have been caught by the first
+                % if-then-else condition that tests Target.
 				error("output_call: calling label")
 			;
 				NeedsPrefix = yes,
 				Wrapper = none,
-				io__write_string("MR_np_call_localret(",
-					!IO),
+                io__write_string("MR_np_call_localret(", !IO),
 				output_code_addr_from_pieces(BaseStr,
 					NeedsPrefix, Wrapper, !IO),
 				io__write_string(",\n\t\t", !IO),
@@ -3933,11 +3877,12 @@
 		io__write_string(",\n\t\t", !IO),
 		output_code_addr(Continuation, !IO)
 	),
-	( ProfileCall = yes ->
+    (
+        ProfileCall = yes,
 		io__write_string(",\n\t\t", !IO),
 		output_label_as_code_addr(CallerLabel, !IO)
 	;
-		true
+        ProfileCall = no
 	),
 	io__write_string(");\n", !IO).
 
@@ -3945,7 +3890,10 @@
 	code_addr_to_string_base(CodeAddr, BaseStr, NeedsPrefix, Wrapper),
 	output_code_addr_from_pieces(BaseStr, NeedsPrefix, Wrapper, !IO).
 
-:- type wrapper --->	entry ; label ; none.
+:- type wrapper
+    --->    entry
+    ;       label
+    ;       none.
 
 :- pred output_code_addr_from_pieces(string::in, bool::in, wrapper::in,
 	io::di, io::uo) is det.
@@ -4020,15 +3968,26 @@
 	BaseStr = "MR_do_trace_redo_fail_shallow".
 code_addr_to_string_base(do_trace_redo_fail_deep, BaseStr, no, entry) :-
 	BaseStr = "MR_do_trace_redo_fail_deep".
-code_addr_to_string_base(do_call_closure, BaseStr, no, entry) :-
-	BaseStr = "mercury__do_call_closure_compact".
-code_addr_to_string_base(do_call_class_method, BaseStr, no, entry) :-
-	BaseStr = "mercury__do_call_class_method_compact".
+code_addr_to_string_base(do_call_closure(Variant), BaseStr, no, entry) :-
+    BaseStr = "mercury__do_call_closure_"
+        ++ ho_call_variant_to_string(Variant).
+code_addr_to_string_base(do_call_class_method(Variant), BaseStr, no, entry) :-
+    BaseStr = "mercury__do_call_class_method_"
+        ++ ho_call_variant_to_string(Variant).
 code_addr_to_string_base(do_not_reached, BaseStr, no, entry) :-
 	BaseStr = "MR_do_not_reached".
 
-	% Output a maybe data address, with a `no' meaning NULL.
+ho_call_variant_to_string(Variant) = Str :-
+    (
+        Variant = generic,
+        Str = "compact"
+    ;
+        Variant = specialized_known(Num),
+        Str = int_to_string(Num)
+    ).
 
+    % Output a maybe data address, with a `no' meaning NULL.
+    %
 :- pred output_maybe_data_addr(maybe(data_addr)::in, io::di, io::uo) is det.
 
 output_maybe_data_addr(MaybeDataAddr, !IO) :-
@@ -4041,7 +4000,7 @@
 	).
 
 	% Output a list of maybe data addresses, with a `no' meaning NULL.
-
+    %
 :- pred output_maybe_data_addrs(list(maybe(data_addr))::in, io::di, io::uo)
 	is det.
 
@@ -4053,7 +4012,7 @@
 	io__write_string("\n", !IO).
 
 	% Output a list of data addresses.
-
+    %
 :- pred output_data_addrs(list(data_addr)::in, io::di, io::uo) is det.
 
 output_data_addrs([], !IO).
@@ -4063,7 +4022,7 @@
 	io__write_string("\n", !IO).
 
 	% Output a data address.
-
+    %
 output_data_addr(data_addr(ModuleName, DataName), !IO) :-
 	output_data_addr(ModuleName, DataName, !IO).
 output_data_addr(rtti_addr(RttiId), !IO) :-
@@ -4240,14 +4199,14 @@
 	io__write_int(Tag, !IO),
 	io__write_string(")", !IO).
 
-	% output an rval, converted to the specified type
+    % Output an rval, converted to the specified type
 	%
 :- pred output_rval_as_type(rval::in, llds_type::in, io::di, io::uo) is det.
 
 output_rval_as_type(Rval, DesiredType, !IO) :-
 	llds__rval_type(Rval, ActualType),
 	( types_match(DesiredType, ActualType) ->
-		% no casting needed
+        % No casting needed.
 		output_rval(Rval, !IO)
 	;
 		% We need to convert to the right type first.
@@ -4279,7 +4238,7 @@
 				% very substantial (in the range of megabytes).
 				output_int_const(N, DesiredType, !IO)
 			;
-				% cast value to desired type
+                % Cast value to desired type.
 				output_llds_type_cast(DesiredType, !IO),
 				output_rval(Rval, !IO)
 			)
@@ -4326,31 +4285,28 @@
 direct_field_int_constant(code_ptr) = no.
 direct_field_int_constant(word) = no.
 
-	% output a float rval, converted to type `MR_Word *'
+    % Output a float rval, converted to type `MR_Word *'
 	%
 :- pred output_float_rval_as_data_ptr(rval::in, io::di, io::uo) is det.
 
 output_float_rval_as_data_ptr(Rval, !IO) :-
 	output_float_rval(Rval, yes, !IO).
 
-	% output a float rval, converted to type `MR_Word'
+    % Output a float rval, converted to type `MR_Word'
 	%
 :- pred output_float_rval_as_word(rval::in, io::di, io::uo) is det.
 
 output_float_rval_as_word(Rval, !IO) :-
 	output_float_rval(Rval, no, !IO).
 
-	% output a float rval, converted to type `MR_Word' or `MR_Word *'
+    % Output a float rval, converted to type `MR_Word' or `MR_Word *'
 	%
 :- pred output_float_rval(rval::in, bool::in, io::di, io::uo) is det.
 
 output_float_rval(Rval, IsPtr, !IO) :-
-	%
-	% for float constant expressions, if we're using boxed
-	% boxed floats and --static-ground-terms is enabled,
-	% we just refer to the static const which we declared
-	% earlier
-	%
+    % For float constant expressions, if we're using boxed boxed floats
+    % and --static-ground-terms is enabled, we just refer to the static const
+    % which we declared earlier.
 	globals__io_lookup_bool_option(unboxed_float, UnboxFloat, !IO),
 	globals__io_lookup_bool_option(static_ground_terms, StaticGroundTerms,
 		!IO),
@@ -4690,15 +4646,17 @@
 		io__write_string(")", !IO)
 	).
 output_rval(lval(Lval), !IO) :-
-	% if a field is used as an rval, then we need to use
-	% the MR_const_field() macro or its variants, not the MR_field() macro
-	% or its variants, to avoid warnings about discarding const.
+    % If a field is used as an rval, then we need to use the MR_const_field()
+    % macro or its variants, not the MR_field() macro or its variants,
+    % to avoid warnings about discarding const.
 	( Lval = field(MaybeTag, Rval, FieldNumRval) ->
-		( MaybeTag = yes(Tag) ->
+        (
+            MaybeTag = yes(Tag),
 			io__write_string("MR_ctfield(", !IO),
 			io__write_int(Tag, !IO),
 			io__write_string(", ", !IO)
 		;
+            MaybeTag = no,
 			io__write_string("MR_const_mask_field(", !IO)
 		),
 		output_rval(Rval, !IO),
@@ -4749,15 +4707,13 @@
 :- pred output_rval_const(rval_const::in, io::di, io::uo) is det.
 
 output_rval_const(int_const(N), !IO) :-
-	% we need to cast to (Integer) to ensure
-	% things like 1 << 32 work when `Integer' is 64 bits
-	% but `int' is 32 bits.
+    % We need to cast to (Integer) to ensure things like 1 << 32 work
+    % when `Integer' is 64 bits but `int' is 32 bits.
 	output_llds_type_cast(integer, !IO),
 	io__write_int(N, !IO).
 output_rval_const(float_const(FloatVal), !IO) :-
-	% the cast to (Float) here lets the C compiler
-	% do arithmetic in `float' rather than `double'
-	% if `Float' is `float' not `double'.
+    % The cast to (Float) here lets the C compiler do arithmetic in `float'
+    % rather than `double' if `Float' is `float' not `double'.
 	output_llds_type_cast(float, !IO),
 	c_util__output_float_literal(FloatVal, !IO).
 output_rval_const(string_const(String), !IO) :-
@@ -4780,9 +4736,8 @@
 output_rval_const(code_addr_const(CodeAddress), !IO) :-
 	output_code_addr(CodeAddress, !IO).
 output_rval_const(data_addr_const(DataAddr, MaybeOffset), !IO) :-
-	% Data addresses are all assumed to be of type `MR_Word *';
-	% we need to cast them here to avoid type errors. The offset
-	% is also in MR_Words.
+    % Data addresses are all assumed to be of type `MR_Word *'; we need to
+    % cast them here to avoid type errors. The offset is also in MR_Words.
 	(
 		MaybeOffset = no,
 		% The tests for special cases below increase the runtime
@@ -4862,8 +4817,8 @@
 		->
 			io__write_string("MR_BOOL_CTOR_ADDR", !IO)
 		;
-			io__write_strings(["MR_CTOR0_ADDR(", ModuleStr, ", ",
-				Name, ")"], !IO)
+            io__write_strings(["MR_CTOR0_ADDR(", ModuleStr, ", ", Name, ")"],
+                !IO)
 		)
 	; Arity = 1 ->
 		(
@@ -4877,8 +4832,8 @@
 		->
 			io__write_string("MR_TYPE_INFO_CTOR_ADDR", !IO)
 		;
-			io__write_strings(["MR_CTOR1_ADDR(", ModuleStr, ", ",
-				Name, ")"], !IO)
+            io__write_strings(["MR_CTOR1_ADDR(", ModuleStr, ", ", Name, ")"],
+                !IO)
 		)
 	;
 		io__write_strings(["MR_CTOR_ADDR(", ModuleStr, ", ", Name,
@@ -4892,7 +4847,7 @@
 	( types_match(word, ActualType) ->
 		output_lval(Lval, !IO)
 	; ActualType = float ->
-		% sanity check -- if this happens, the llds is ill-typed
+        % Sanity check -- if this happens, the LLDS is ill-typed.
 		error("output_lval_as_word: got float")
 	;
 		io__write_string("MR_LVALUE_CAST(MR_Word,", !IO),
Index: compiler/opt_debug.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/opt_debug.m,v
retrieving revision 1.152
diff -u -b -r1.152 opt_debug.m
--- compiler/opt_debug.m	25 Aug 2005 03:19:47 -0000	1.152
+++ compiler/opt_debug.m	26 Aug 2005 05:43:37 -0000
@@ -162,7 +162,7 @@
 
 dump_instrs_2([], _PrintComments, !IO).
 dump_instrs_2([Uinstr - Comment | Instrs], PrintComments, !IO) :-
-    output_instruction_and_comment(Uinstr, Comment, PrintComments, !IO),
+    output_debug_instruction_and_comment(Uinstr, Comment, PrintComments, !IO),
     dump_instrs_2(Instrs, PrintComments, !IO).
 
 dump_intlist([]) = "".
@@ -482,29 +482,18 @@
 dump_code_addr(do_trace_redo_fail_shallow) =
     "do_trace_redo_fail_shallow".
 dump_code_addr(do_trace_redo_fail_deep) = "do_trace_redo_fail_deep".
-dump_code_addr(do_call_closure) = "do_nondet_closure".
-dump_code_addr(do_call_class_method) = "do_nondet_class_method".
+dump_code_addr(do_call_closure(Variant)) =
+    "do_call_closure_" ++ ho_call_variant_to_string(Variant).
+dump_code_addr(do_call_class_method(Variant)) =
+    "do_call_class_method_" ++ ho_call_variant_to_string(Variant).
 dump_code_addr(do_not_reached) = "do_not_reached".
 
-dump_code_addr(ProcLabel, label(Label)) = dump_label(ProcLabel, Label).
-dump_code_addr(_, imported(ProcLabel)) = dump_proclabel(ProcLabel).
-dump_code_addr(_, succip) = "succip".
-dump_code_addr(_, do_succeed(Last)) = Str :-
-    (
-        Last = no,
-        Str = "do_succeed"
+dump_code_addr(ProcLabel, CodeAddr) =
+    ( CodeAddr = label(Label) ->
+        dump_label(ProcLabel, Label)
     ;
-        Last = yes,
-        Str = "do_last_succeed"
+        dump_code_addr(CodeAddr)
     ).
-dump_code_addr(_, do_redo) = "do_redo".
-dump_code_addr(_, do_fail) = "do_fail".
-dump_code_addr(_, do_trace_redo_fail_shallow) =
-    "do_trace_redo_fail_shallow".
-dump_code_addr(_, do_trace_redo_fail_deep) = "do_trace_redo_fail_deep".
-dump_code_addr(_, do_call_closure) = "do_nondet_closure".
-dump_code_addr(_, do_call_class_method) = "do_nondet_class_method".
-dump_code_addr(_, do_not_reached) = "do_not_reached".
 
 dump_code_addrs([]) = "".
 dump_code_addrs([Addr | Addrs]) =
Index: compiler/opt_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/opt_util.m,v
retrieving revision 1.131
diff -u -b -r1.131 opt_util.m
--- compiler/opt_util.m	8 Jul 2005 04:22:05 -0000	1.131
+++ compiler/opt_util.m	25 Aug 2005 12:15:24 -0000
@@ -1325,8 +1325,8 @@
 livevals_addr(do_fail, no).
 livevals_addr(do_trace_redo_fail_shallow, no).
 livevals_addr(do_trace_redo_fail_deep, no).
-livevals_addr(do_call_closure, yes).
-livevals_addr(do_call_class_method, yes).
+livevals_addr(do_call_closure(_), yes).
+livevals_addr(do_call_class_method(_), yes).
 livevals_addr(do_not_reached, no).
 
 count_temps_instr_list([], !R, !F).
@@ -1974,9 +1974,10 @@
 	do_trace_redo_fail_shallow).
 replace_labels_code_addr(do_trace_redo_fail_deep, _,
 	do_trace_redo_fail_deep).
-replace_labels_code_addr(do_call_closure, _, do_call_closure).
-replace_labels_code_addr(do_call_class_method, _,
-	do_call_class_method).
+replace_labels_code_addr(do_call_closure(MaybeSpec), _,
+		do_call_closure(MaybeSpec)).
+replace_labels_code_addr(do_call_class_method(MaybeSpec), _,
+		do_call_class_method(MaybeSpec)).
 replace_labels_code_addr(do_not_reached, _, do_not_reached).
 
 :- pred replace_labels_label_list(list(label)::in,
Index: compiler/options.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.463
diff -u -b -r1.463 options.m
--- compiler/options.m	25 Aug 2005 03:19:47 -0000	1.463
+++ compiler/options.m	27 Aug 2005 01:43:59 -0000
@@ -433,6 +433,8 @@
 		;	num_real_f_temps
 		;	pic
 		;	max_jump_table_size
+		;	max_specialized_do_call_closure
+		;	max_specialized_do_call_class_method
 		;	compare_specialization
 		;	fact_table_max_array_size
 				% maximum number of elements in a single
@@ -1092,6 +1094,14 @@
 	pic			-	bool(no),
 	max_jump_table_size	-	int(0),
 					% 0 indicates any size.
+	max_specialized_do_call_closure - int(3),
+					% mercury__do_call_closure_N
+					% exists for N <= option_value;
+					% set to -1 to disable.
+	max_specialized_do_call_class_method - int(-1),
+					% mercury__do_call_class_method_N
+					% exists for N <= option_value;
+					% set to -1 to disable.
 	compare_specialization	-	int(-1),
 					% -1 asks handle_options.m to give
 					% the value, which may be grade
@@ -1768,6 +1778,10 @@
 long_option("num-real-f-temps",		num_real_f_temps).
 long_option("num-real-temps",		num_real_r_temps).	% obsolete
 long_option("max-jump-table-size",	max_jump_table_size).
+% long_option("max-spec-do-call-closure",
+%					max_specialized_do_call_closure).
+% long_option("max-spec-do-call-class-method",
+%					max_specialized_do_call_class_method).
 long_option("compare-specialization",	compare_specialization).
 long_option("fact-table-max-array-size",fact_table_max_array_size).
 long_option("fact-table-hash-percent-full",
Index: compiler/tupling.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/tupling.m,v
retrieving revision 1.9
diff -u -b -r1.9 tupling.m
--- compiler/tupling.m	12 Aug 2005 05:14:16 -0000	1.9
+++ compiler/tupling.m	25 Aug 2005 14:58:51 -0000
@@ -1036,7 +1036,7 @@
 	).
 
 count_load_stores_in_goal(Goal - GoalInfo, CountInfo, !CountState) :-
-	Goal = generic_call(GenericCall, ArgVars, ArgModes, Detism),
+	Goal = generic_call(GenericCall, ArgVars, ArgModes, _Detism),
 	ProcInfo = CountInfo ^ count_info_proc,
 	ModuleInfo = CountInfo ^ count_info_module,
 	goal_info_get_maybe_need_across_call(GoalInfo, MaybeNeedAcrossCall),
@@ -1044,15 +1044,15 @@
 	list__map(map__lookup(VarTypes), ArgVars, ArgTypes),
 	arg_info__compute_in_and_out_vars(ModuleInfo, ArgVars,
 		ArgModes, ArgTypes, InputArgs, OutputArgs),
-	determinism_to_code_model(Detism, CodeModel),
 
 	% Casts are generated inline.
 	( GenericCall = cast(_) ->
 		cls_require_in_regs(CountInfo, InputArgs, !CountState),
 		cls_put_in_regs(OutputArgs, !CountState)
 	;
-		call_gen__generic_call_info(CodeModel, GenericCall, _,
-			GenericVarsArgInfos, _),
+		module_info_globals(ModuleInfo, Globals),
+		call_gen__generic_call_info(Globals, GenericCall,
+			length(InputArgs), _, GenericVarsArgInfos, _, _),
 		assoc_list__keys(GenericVarsArgInfos, GenericVars),
 		list__append(GenericVars, InputArgs, Inputs),
 		set__list_to_set(OutputArgs, Outputs),
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_glut
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
cvs diff: Diffing mdbcomp
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
Index: runtime/mercury_conf_param.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_conf_param.h,v
retrieving revision 1.82
diff -u -b -r1.82 mercury_conf_param.h
--- runtime/mercury_conf_param.h	3 Jun 2005 07:04:22 -0000	1.82
+++ runtime/mercury_conf_param.h	27 Aug 2005 11:55:58 -0000
@@ -344,6 +344,11 @@
 ** uses which occur inside debugging routines, so to get an accurate
 ** count you should not also enable low-level debugging.)
 **
+** MR_DO_CALL_STATS
+** Enable this is you want to collect statistics about the number of arguments
+** hidden inside closures. The stats will be appended to the file named by the
+** HO_CALL_STATS environment variable.
+**
 ** MR_MPROF_PROFILE_CALLS
 ** Enables call count profiling for mprof.
 **
Index: runtime/mercury_ho_call.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_ho_call.c,v
retrieving revision 1.75
diff -u -b -r1.75 mercury_ho_call.c
--- runtime/mercury_ho_call.c	26 Aug 2005 00:54:24 -0000	1.75
+++ runtime/mercury_ho_call.c	28 Aug 2005 08:24:57 -0000
@@ -336,6 +336,10 @@
 ** The placement of the extra input arguments into MR_r3, MR_r4 etc is done by
 ** the code generator, as is the movement of the output arguments to their
 ** eventual destinations.
+**
+** Each do_call_closure_N variant is specialized for the case where the number
+** of additional input arguments is N. When calling them, the code generator
+** puts the additional arguments (if any) in MR_r2, MR_r3 etc.
 */
 
     /*
@@ -353,12 +357,89 @@
     */
 #define MR_CLASS_METHOD_CALL_INPUTS_COMPACT 3
 
+#ifdef MR_DO_CALL_STATS
+#define MR_MAX_STATS_ARG 100
+
+static unsigned int    MR_explicit_closure_arg_histogram[MR_MAX_STATS_ARG];
+static unsigned int    MR_explicit_method_arg_histogram[MR_MAX_STATS_ARG];
+static unsigned int    MR_hidden_closure_arg_histogram[MR_MAX_STATS_ARG];
+static unsigned int    MR_hidden_method_arg_histogram[MR_MAX_STATS_ARG];
+
+#define MR_maybe_record_closure_histogram(exp, hid)                           \
+    do {                                                                      \
+        if (exp < MR_MAX_STATS_ARG) {                                         \
+            MR_explicit_closure_arg_histogram[exp]++;                         \
+        }                                                                     \
+        if (hid < MR_MAX_STATS_ARG) {                                         \
+            MR_hidden_closure_arg_histogram[hid]++;                           \
+        }                                                                     \
+    } while (0)
+
+#define MR_maybe_record_method_histogram(exp, hid)                            \
+    do {                                                                      \
+        if (exp < MR_MAX_STATS_ARG) {                                         \
+            MR_explicit_method_arg_histogram[exp]++;                          \
+        }                                                                     \
+        if (hid < MR_MAX_STATS_ARG) {                                         \
+            MR_hidden_method_arg_histogram[hid]++;                            \
+        }                                                                     \
+    } while (0)
+
+void
+MR_print_hidden_arg_stats(FILE *fp)
+{
+    int i;
+
+    for (i = 0; i < MR_MAX_STATS_ARG; i++) {
+        if (MR_explicit_closure_arg_histogram[i] > 0) {
+            fprintf(fp, "closure invocations with %d explicit args: %d\n",
+                i, MR_explicit_closure_arg_histogram[i]);
+        }
+    }
+
+    for (i = 0; i < MR_MAX_STATS_ARG; i++) {
+        if (MR_explicit_method_arg_histogram[i] > 0) {
+            fprintf(fp, "method invocations with %d explicit args: %d\n",
+                i, MR_explicit_method_arg_histogram[i]);
+        }
+    }
+
+    for (i = 0; i < MR_MAX_STATS_ARG; i++) {
+        if (MR_hidden_closure_arg_histogram[i] > 0) {
+            fprintf(fp, "closure invocations with %d hidden args: %d\n",
+                i, MR_hidden_closure_arg_histogram[i]);
+        }
+    }
+
+    for (i = 0; i < MR_MAX_STATS_ARG; i++) {
+        if (MR_hidden_method_arg_histogram[i] > 0) {
+            fprintf(fp, "method invocations with %d hidden args: %d\n",
+                i, MR_hidden_method_arg_histogram[i]);
+        }
+    }
+}
+
+#else
+
+#define MR_maybe_record_closure_histogram(exp, hid)     ((void) 0)
+#define MR_maybe_record_method_histogram(exp, hid)      ((void) 0)
+
+#endif
+
 /*
 ** These are the real implementations of higher order calls and method calls.
 */
 
 MR_define_extern_entry(mercury__do_call_closure_compact);
+MR_define_extern_entry(mercury__do_call_closure_0);
+MR_define_extern_entry(mercury__do_call_closure_1);
+MR_define_extern_entry(mercury__do_call_closure_2);
+MR_define_extern_entry(mercury__do_call_closure_3);
 MR_define_extern_entry(mercury__do_call_class_method_compact);
+MR_define_extern_entry(mercury__do_call_class_method_0);
+MR_define_extern_entry(mercury__do_call_class_method_1);
+MR_define_extern_entry(mercury__do_call_class_method_2);
+MR_define_extern_entry(mercury__do_call_class_method_3);
 
 /*
 ** These are the real implementations of unify and compare.
@@ -374,7 +455,15 @@
 
 MR_BEGIN_MODULE(call_module)
     MR_init_entry_an(mercury__do_call_closure_compact);
+    MR_init_entry_an(mercury__do_call_closure_0);
+    MR_init_entry_an(mercury__do_call_closure_1);
+    MR_init_entry_an(mercury__do_call_closure_2);
+    MR_init_entry_an(mercury__do_call_closure_3);
     MR_init_entry_an(mercury__do_call_class_method_compact);
+    MR_init_entry_an(mercury__do_call_class_method_0);
+    MR_init_entry_an(mercury__do_call_class_method_1);
+    MR_init_entry_an(mercury__do_call_class_method_2);
+    MR_init_entry_an(mercury__do_call_class_method_3);
 
     MR_init_entry_an(mercury__builtin__unify_2_0);
     MR_init_entry_an(mercury__builtin__compare_3_0);
@@ -385,39 +474,49 @@
 MR_BEGIN_CODE
 
 /*
-** Note: this routine gets ignored for profiling.
-** That means it should be called using noprof_call()
-** rather than call().  See comment in output_call in
-** compiler/llds_out for explanation.
+** The following comments apply to all variants of do_call_closure and
+** do_call_class_method.
+**
+** Each of the following routines starts by picking up its input arguments
+** from Mercury abstract machine registers and putting them in local variables.
+** This allows the values of these arguments to be printed in gdb without
+** worrying about which real machine registers, if any, hold them.
+**
+** Also note that in each case, when we invoke the higher order value,
+** we pass MR_prof_ho_caller_proc as the second argument of MR_tailcall
+** instead of the name of the routine itself, so that the call gets recorded
+** as having come from our caller.
+**
+** Each of these routines get ignored for profiling. That means they should be
+** called using noprof_call() rather than call(). See the comment in
+** output_call in compiler/llds_out for the explanation.
+**
+** Any change in one variant probably has to be made in all variants.
 */
+
 MR_define_entry(mercury__do_call_closure_compact);
 {
     MR_Closure  *closure;
-    int         num_extra_args; /* # of args provided by our caller */
+    int         num_input_args; /* # of args provided by our caller */
     int         num_hidden_args;/* # of args hidden in the closure  */
     int         i;
 
-    /*
-    ** These assignments to local variables allow the values
-    ** of the relevant registers to be printed in gdb without
-    ** worrying about which machine registers, if any, hold them.
-    */
-
     closure = (MR_Closure *) MR_r1;
-    num_extra_args = MR_r2;
+    num_input_args = MR_r2;
     num_hidden_args = closure->MR_closure_num_hidden_args;
+    MR_maybe_record_closure_histogram(num_input_args, num_hidden_args);
 
     MR_save_registers();
 
     if (num_hidden_args < MR_HO_CALL_INPUTS_COMPACT) {
         /* copy to the left, from the left */
-        for (i = 1; i <= num_extra_args; i++) {
+        for (i = 1; i <= num_input_args; i++) {
             MR_virtual_reg_assign(i + num_hidden_args,
                 MR_virtual_reg_value(i + MR_HO_CALL_INPUTS_COMPACT));
         }
     } else if (num_hidden_args > MR_HO_CALL_INPUTS_COMPACT) {
         /* copy to the right, from the right */
-        for (i = num_extra_args; i > 0; i--) {
+        for (i = num_input_args; i > 0; i--) {
             MR_virtual_reg_assign(i + num_hidden_args,
                 MR_virtual_reg_value(i + MR_HO_CALL_INPUTS_COMPACT));
         }
@@ -429,75 +528,285 @@
 
     MR_restore_registers();
 
-    /*
-    ** Note that we pass MR_prof_ho_caller_proc rather than
-    ** MR_LABEL(mercury__do_call_closure_compact), so that the call
-    ** gets recorded as having come from our caller.
-    */
     MR_tailcall(closure->MR_closure_code, MR_prof_ho_caller_proc);
 }
 
-/*
-** Note: this routine gets ignored for profiling.
-** That means it should be called using noprof_call()
-** rather than call().  See comment in output_call in
-** compiler/llds_out for explanation.
-*/
+MR_define_entry(mercury__do_call_closure_0);
+{
+    MR_Closure  *closure;
+    int         num_hidden_args;/* # of args hidden in the closure  */
+    int         i;
+
+    closure = (MR_Closure *) MR_r1;
+    num_hidden_args = closure->MR_closure_num_hidden_args;
+    MR_maybe_record_closure_histogram(0, num_hidden_args);
+
+    MR_save_registers();
+
+    for (i = 1; i <= num_hidden_args; i++) {
+        MR_virtual_reg_assign(i, closure->MR_closure_hidden_args(i));
+    }
+
+    MR_restore_registers();
+
+    MR_tailcall(closure->MR_closure_code, MR_prof_ho_caller_proc);
+}
+
+MR_define_entry(mercury__do_call_closure_1);
+{
+    MR_Closure  *closure;
+    int         num_hidden_args;/* # of args hidden in the closure  */
+    int         i;
+    MR_Word     arg1;
+
+    closure = (MR_Closure *) MR_r1;
+    arg1 = MR_r2;
+    num_hidden_args = closure->MR_closure_num_hidden_args;
+    MR_maybe_record_closure_histogram(1, num_hidden_args);
+
+    MR_save_registers();
+
+    MR_virtual_reg_assign(num_hidden_args + 1, arg1);
+    for (i = 1; i <= num_hidden_args; i++) {
+        MR_virtual_reg_assign(i, closure->MR_closure_hidden_args(i));
+    }
+
+    MR_restore_registers();
+
+    MR_tailcall(closure->MR_closure_code, MR_prof_ho_caller_proc);
+}
+
+MR_define_entry(mercury__do_call_closure_2);
+{
+    MR_Closure  *closure;
+    int         num_hidden_args;/* # of args hidden in the closure  */
+    int         i;
+    MR_Word     arg1;
+    MR_Word     arg2;
+
+    closure = (MR_Closure *) MR_r1;
+    arg1 = MR_r2;
+    arg2 = MR_r3;
+    num_hidden_args = closure->MR_closure_num_hidden_args;
+    MR_maybe_record_closure_histogram(2, num_hidden_args);
+
+    MR_save_registers();
+
+    MR_virtual_reg_assign(num_hidden_args + 1, arg1);
+    MR_virtual_reg_assign(num_hidden_args + 2, arg2);
+    for (i = 1; i <= num_hidden_args; i++) {
+        MR_virtual_reg_assign(i, closure->MR_closure_hidden_args(i));
+    }
+
+    MR_restore_registers();
+
+    MR_tailcall(closure->MR_closure_code, MR_prof_ho_caller_proc);
+}
+
+MR_define_entry(mercury__do_call_closure_3);
+{
+    MR_Closure  *closure;
+    int         num_hidden_args;/* # of args hidden in the closure  */
+    int         i;
+    MR_Word     arg1;
+    MR_Word     arg2;
+    MR_Word     arg3;
+
+    closure = (MR_Closure *) MR_r1;
+    arg1 = MR_r2;
+    arg2 = MR_r3;
+    arg3 = MR_r4;
+    num_hidden_args = closure->MR_closure_num_hidden_args;
+    MR_maybe_record_closure_histogram(3, num_hidden_args);
+
+    MR_save_registers();
+
+    MR_virtual_reg_assign(num_hidden_args + 1, arg1);
+    MR_virtual_reg_assign(num_hidden_args + 2, arg2);
+    MR_virtual_reg_assign(num_hidden_args + 3, arg3);
+    for (i = 1; i <= num_hidden_args; i++) {
+        MR_virtual_reg_assign(i, closure->MR_closure_hidden_args(i));
+    }
+
+    MR_restore_registers();
+
+    MR_tailcall(closure->MR_closure_code, MR_prof_ho_caller_proc);
+}
+
 MR_define_entry(mercury__do_call_class_method_compact);
 {
     MR_Word     type_class_info;
     MR_Integer  method_index;
     MR_Integer  num_input_args;
-    MR_Code     *destination;
-    MR_Integer  num_extra_instance_args;
+    MR_Integer  num_hidden_args;
+    MR_Code     *dest;
     int         i;
 
-    /*
-    ** These assignments to local variables allow the values
-    ** of the relevant registers to be printed in gdb without
-    ** worrying about which machine registers, if any, hold them.
-    */
-
     type_class_info = MR_r1;
     method_index = (MR_Integer) MR_r2;
     num_input_args = MR_r3;
 
-    destination = MR_typeclass_info_class_method(type_class_info,
-        method_index);
-    num_extra_instance_args = (MR_Integer)
+    dest = MR_typeclass_info_class_method(type_class_info, method_index);
+    num_hidden_args = (MR_Integer)
         MR_typeclass_info_num_extra_instance_args(type_class_info);
+    MR_maybe_record_method_histogram(num_input_args, num_hidden_args);
 
     MR_save_registers();
 
-    if (num_extra_instance_args < MR_CLASS_METHOD_CALL_INPUTS_COMPACT) {
+    if (num_hidden_args < MR_CLASS_METHOD_CALL_INPUTS_COMPACT) {
         /* copy to the left, from the left */
         for (i = 1; i <= num_input_args; i++) {
-            MR_virtual_reg_assign(i + num_extra_instance_args,
+            MR_virtual_reg_assign(i + num_hidden_args,
                 MR_virtual_reg_value(i + MR_CLASS_METHOD_CALL_INPUTS_COMPACT));
         }
-    } else if (num_extra_instance_args >
+    } else if (num_hidden_args >
             MR_CLASS_METHOD_CALL_INPUTS_COMPACT)
     {
         /* copy to the right, from the right */
         for (i = num_input_args; i > 0; i--) {
-            MR_virtual_reg_assign(i + num_extra_instance_args,
+            MR_virtual_reg_assign(i + num_hidden_args,
                 MR_virtual_reg_value(i + MR_CLASS_METHOD_CALL_INPUTS_COMPACT));
         }
     } /* else the new args are in the right place */
 
-    for (i = num_extra_instance_args; i > 0; i--) {
+    for (i = num_hidden_args; i > 0; i--) {
         MR_virtual_reg_assign(i,
-            MR_typeclass_info_extra_instance_arg(MR_virtual_reg_value(1), i));
+            MR_typeclass_info_extra_instance_arg(type_class_info, i));
     }
 
     MR_restore_registers();
 
-    /*
-    ** Note that we pass MR_prof_ho_caller_proc rather than
-    ** MR_LABEL(mercury__do_call_class_method_compact), so that
-    ** the call gets recorded as having come from our caller.
-    */
-    MR_tailcall(destination, MR_prof_ho_caller_proc);
+    MR_tailcall(dest, MR_prof_ho_caller_proc);
+}
+
+MR_define_entry(mercury__do_call_class_method_0);
+{
+    MR_Word     type_class_info;
+    MR_Integer  method_index;
+    MR_Integer  num_hidden_args;
+    MR_Code     *dest;
+    int         i;
+
+    type_class_info = MR_r1;
+    method_index = (MR_Integer) MR_r2;
+
+    dest = MR_typeclass_info_class_method(type_class_info, method_index);
+    num_hidden_args = (MR_Integer)
+        MR_typeclass_info_num_extra_instance_args(type_class_info);
+    MR_maybe_record_method_histogram(0, num_hidden_args);
+
+    MR_save_registers();
+
+    for (i = num_hidden_args; i > 0; i--) {
+        MR_virtual_reg_assign(i,
+            MR_typeclass_info_extra_instance_arg(type_class_info, i));
+    }
+
+    MR_restore_registers();
+
+    MR_tailcall(dest, MR_prof_ho_caller_proc);
+}
+
+MR_define_entry(mercury__do_call_class_method_1);
+{
+    MR_Word     type_class_info;
+    MR_Integer  method_index;
+    MR_Integer  num_hidden_args;
+    MR_Code     *dest;
+    int         i;
+    MR_Word     arg1;
+
+    type_class_info = MR_r1;
+    method_index = (MR_Integer) MR_r2;
+    arg1 = MR_r3;
+
+    dest = MR_typeclass_info_class_method(type_class_info, method_index);
+    num_hidden_args = (MR_Integer)
+        MR_typeclass_info_num_extra_instance_args(type_class_info);
+    MR_maybe_record_method_histogram(1, num_hidden_args);
+
+    MR_save_registers();
+
+    MR_virtual_reg_assign(num_hidden_args + 1, arg1);
+    for (i = num_hidden_args; i > 0; i--) {
+        MR_virtual_reg_assign(i,
+            MR_typeclass_info_extra_instance_arg(type_class_info, i));
+    }
+
+    MR_restore_registers();
+
+    MR_tailcall(dest, MR_prof_ho_caller_proc);
+}
+
+MR_define_entry(mercury__do_call_class_method_2);
+{
+    MR_Word     type_class_info;
+    MR_Integer  method_index;
+    MR_Integer  num_hidden_args;
+    MR_Code     *dest;
+    int         i;
+    MR_Word     arg1;
+    MR_Word     arg2;
+
+    type_class_info = MR_r1;
+    method_index = (MR_Integer) MR_r2;
+    arg1 = MR_r3;
+    arg2 = MR_r4;
+
+    dest = MR_typeclass_info_class_method(type_class_info, method_index);
+    num_hidden_args = (MR_Integer)
+        MR_typeclass_info_num_extra_instance_args(type_class_info);
+    MR_maybe_record_method_histogram(2, num_hidden_args);
+
+    MR_save_registers();
+
+    MR_virtual_reg_assign(num_hidden_args + 1, arg1);
+    MR_virtual_reg_assign(num_hidden_args + 2, arg2);
+    for (i = num_hidden_args; i > 0; i--) {
+        MR_virtual_reg_assign(i,
+            MR_typeclass_info_extra_instance_arg(type_class_info, i));
+    }
+
+    MR_restore_registers();
+
+    MR_tailcall(dest, MR_prof_ho_caller_proc);
+}
+
+MR_define_entry(mercury__do_call_class_method_3);
+{
+    MR_Word     type_class_info;
+    MR_Integer  method_index;
+    MR_Integer  num_hidden_args;
+    MR_Code     *dest;
+    int         i;
+    MR_Word     arg1;
+    MR_Word     arg2;
+    MR_Word     arg3;
+
+    type_class_info = MR_r1;
+    method_index = (MR_Integer) MR_r2;
+    arg1 = MR_r3;
+    arg2 = MR_r4;
+    arg3 = MR_r5;
+
+    dest = MR_typeclass_info_class_method(type_class_info, method_index);
+    num_hidden_args = (MR_Integer)
+        MR_typeclass_info_num_extra_instance_args(type_class_info);
+    MR_maybe_record_method_histogram(3, num_hidden_args);
+
+    MR_save_registers();
+
+    MR_virtual_reg_assign(num_hidden_args + 1, arg1);
+    MR_virtual_reg_assign(num_hidden_args + 2, arg2);
+    MR_virtual_reg_assign(num_hidden_args + 3, arg3);
+    for (i = num_hidden_args; i > 0; i--) {
+        MR_virtual_reg_assign(i,
+            MR_typeclass_info_extra_instance_arg(type_class_info, i));
+    }
+
+    MR_restore_registers();
+
+    MR_tailcall(dest, MR_prof_ho_caller_proc);
 }
 
 /*
Index: runtime/mercury_ho_call.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_ho_call.h,v
retrieving revision 1.11
diff -u -b -r1.11 mercury_ho_call.h
--- runtime/mercury_ho_call.h	26 Aug 2005 00:54:24 -0000	1.11
+++ runtime/mercury_ho_call.h	27 Aug 2005 04:26:46 -0000
@@ -26,6 +26,9 @@
 #include "mercury_types.h"		    /* for MR_Closure */
 #ifndef	MR_HIGHLEVEL_CODE
   #include "mercury_goto.h"		    /* for MR_declare_entry */
+  #ifdef MR_DO_CALL_STATS
+    #include  <stdio.h>               /* for FILE */
+  #endif
 #endif
 
 /*
@@ -121,6 +124,12 @@
 /* in mercury_types.h: typedef struct MR_Closure_Struct MR_Closure; */
 
 #define	MR_closure_hidden_args(i)	MR_closure_hidden_args_0[(i) - 1]
+
+#ifndef MR_HIGHLEVEL_CODE
+  #ifdef MR_DO_CALL_STATS
+    extern  void            MR_print_hidden_arg_stats(FILE *fp);
+  #endif
+#endif
 
 /*
 ** Build a closure for the given procedure address.
Index: runtime/mercury_mm_own_stacks.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_mm_own_stacks.c,v
retrieving revision 1.3
diff -u -b -r1.3 mercury_mm_own_stacks.c
--- runtime/mercury_mm_own_stacks.c	3 Jun 2005 07:04:22 -0000	1.3
+++ runtime/mercury_mm_own_stacks.c	26 Aug 2005 23:48:02 -0000
@@ -537,7 +537,7 @@
 #else   /* ! MR_HIGHLEVEL_CODE */
 
 MR_define_extern_entry(MR_MMOS_RET_ALL_NONDET_ENTRY);
-MR_define_extern_entry(MR_MMOS_RET_ALL_NONDET_ENTRY);
+MR_define_extern_entry(MR_MMOS_RET_ALL_MULTI_ENTRY);
 
 MR_EXTERN_USER_PROC_ID_PROC_LAYOUT(MR_DETISM_NON, 0, -1, 
     MR_PREDICATE, table_builtin, table_mmos_consume_next_answer_nondet, 2, 0);
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.150
diff -u -b -r1.150 mercury_wrapper.c
--- runtime/mercury_wrapper.c	29 Aug 2005 03:22:30 -0000	1.150
+++ runtime/mercury_wrapper.c	29 Aug 2005 06:11:24 -0000
@@ -1738,6 +1738,22 @@
 	MR_print_register_usage_counts();
 #endif
 
+#ifdef	MR_DO_CALL_STATS
+	{
+		char	*stats_file_name;
+		FILE	*stats_fp;
+
+		stats_file_name = getenv("HO_CALL_STATS");
+		if (stats_file_name != NULL) {
+			stats_fp = fopen(stats_file_name, "a");
+			if (stats_fp != NULL) {
+				MR_print_hidden_arg_stats(stats_fp);
+				(void) fclose(stats_fp);
+			}
+		}
+	}
+#endif
+
         if (use_own_timer) {
 		printf("%8.3fu ",
 			((double) (MR_time_at_finish - MR_time_at_start))
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing slice
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
Index: tools/bootcheck
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/tools/bootcheck,v
retrieving revision 1.174
diff -u -b -r1.174 bootcheck
--- tools/bootcheck	1 Aug 2005 02:26:21 -0000	1.174
+++ tools/bootcheck	28 Aug 2005 08:20:27 -0000
@@ -1138,6 +1138,11 @@
     # Use the new mmake to build stage 3
     MMAKE=$MMAKE_DIR/mmake
 
+    # This setting is ignore unless the stage 2 was compiled with
+    # -DMR_HO_CALL_STATS.
+    HO_CALL_STATS="$root/HO_CALL_STATS"
+    export HO_CALL_STATS
+
     if test "$type_stats" != ""
     then
         # Start collecting statistics from stage 3 with a clean slate,
Index: tools/ho_call_stats
===================================================================
RCS file: tools/ho_call_stats
diff -N tools/ho_call_stats
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/ho_call_stats	28 Aug 2005 11:28:14 -0000
@@ -0,0 +1,42 @@
+#!/bin/sh
+# vim: ts=4 sw=4 et
+awk '
+$1 == "closure" && $5 == "explicit"     { closure_explicit[$4] += $7;   }
+$1 == "closure" && $5 == "hidden"       { closure_hidden[$4] += $7; }
+$1 == "method" && $5 == "explicit"      { method_explicit[$4] += $7;    }
+$1 == "method" && $5 == "hidden"        { method_hidden[$4] += $7;  }
+    {
+        if ($4 > max) {
+            max = $4;
+        }
+    }
+END {
+        for (i = 0; i <= max; i++) {
+            if (closure_explicit[i]) {
+                printf "closure invocations with %2d explicit args: %10d\n", \
+                    i, closure_explicit[i];
+            }
+        }
+
+        for (i = 0; i <= max; i++) {
+            if (closure_hidden[i]) {
+                printf "closure invocations with %2d hidden args:   %10d\n", \
+                    i, closure_hidden[i];
+            }
+        }
+
+        for (i = 0; i <= max; i++) {
+            if (method_explicit[i]) {
+                printf "method  invocations with %2d explicit args: %10d\n", \
+                    i, method_explicit[i];
+            }
+        }
+
+        for (i = 0; i <= max; i++) {
+            if (method_hidden[i]) {
+                printf "method  invocations with %2d hidden args:   %10d\n", \
+                    i, method_hidden[i];
+            }
+        }
+    }
+' "$@"
Index: tools/makebatch
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/tools/makebatch,v
retrieving revision 1.29
diff -u -b -r1.29 makebatch
--- tools/makebatch	17 May 2005 04:32:29 -0000	1.29
+++ tools/makebatch	27 Aug 2005 12:00:59 -0000
@@ -26,13 +26,14 @@
 # that version. When makebatch exits normally, it removes the file to indicate
 # completion.
 
-usage="Usage: makebatch [-jN] [-cdeost] [--compile-times] [--save-stage2-on-error] [--test-params] batchname"
+usage="Usage: makebatch [-jN] [-cdeost] [--compile-times] [--save-stage2-on-error] [--save-stage2-on-no-compiler] [--test-params] batchname"
 jfactor=-j1
 runtests=""
 objects=""
 cfiles="false"
 save_stage2="false"
 save_stage2_on_error="false"
+save_stage2_on_no_compiler="false"
 errfiles="false"
 compile_times=""
 testparams=""
@@ -64,6 +65,9 @@
 	--save-stage2-on-error)
 		save_stage2_on_error="true" ;;
 
+	--save-stage2-on-no-compiler)
+		save_stage2_on_no_compiler="true" ;;
+
 	-s|--stop-at-failure)
 		failed="stop" ;;
 
@@ -205,10 +209,12 @@
 
 	echo starting bootcheck of version $visn
 	succeeded=false
+	created_compiler=false
 	if tools/bootcheck $gradeopt --copy-runtime $jfactor $runtests \
 	   $objects $compile_times $testparams > batch/$batch.out.$visn 2>&1
 	then
 		succeeded=true
+		created_compiler=true
 		echo bootcheck of version $visn succeeded
 		cp stage2/compiler/mercury_compile batch/$batch.mercury_compile.$visn
 		size batch/$batch.mercury_compile.$visn | tail -1 | sed -e 's/mercury_compile.//' | sed -e 's/batch\///' >> batch/$batch.sizes
@@ -221,6 +227,7 @@
 	else
 		if test -x stage2/compiler/mercury_compile
 		then
+			created_compiler=true
 			echo bootcheck of version $visn failed but produced compiler
 			cp stage2/compiler/mercury_compile batch/$batch.mercury_compile.$visn
 			size batch/$batch.mercury_compile.$visn | tail -1 | sed -e 's/mercury_compile.//' | sed -e 's/batch\///' >> batch/$batch.sizes
@@ -278,6 +285,10 @@
 		/bin/rm -fr stage2.batch.$visn > /dev/null
 		mv stage2 stage2.batch.$visn
 	elif $save_stage2_on_error && test $succeeded = false
+	then
+		/bin/rm -fr stage2.batch.$visn > /dev/null
+		mv stage2 stage2.batch.$visn
+	elif $save_stage2_on_no_compiler && test $created_compiler = false
 	then
 		/bin/rm -fr stage2.batch.$visn > /dev/null
 		mv stage2 stage2.batch.$visn
cvs diff: Diffing trace
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list