[m-rev.] for review: parallel liveness and code generation

Peter Wang wangp at students.cs.mu.oz.au
Wed Aug 16 15:46:04 AEST 2006


(Pending much bootchecking.)

For review by Zoltan.  In particular I'd like to know `remap_instr' is not
updating some instructions that require updating (to refer to combined static
cell information), or if some instructions don't need updating.


Estimated hours taken: 20
Branches: main

Add options to perform code generation and liveness detection for the low-level
backend using parallel threads.  These are enabled with `--parallel-code-gen'
and `--parallel-liveness' options respectively, for compilers built in grades
supporting multiple engines, and running with multiple engines enabled.
Currently we only attempt to use two threads.

compiler/global_data.m:
	Use a new type `type_num' instead of `int' everywhere for common cell
	type numbers.

	Add a function `bump_type_num_counter' which takes a global_data
	structure and returns a global_data with the common cell type number
	counter incremented by some amount.  This is to allow multiple threads
	to add new types to their own copies of the global_data structure
	without type numbers clashing when we try to merge them later.

	Add a predicate `merge_global_datas' which takes two global_datas and
	merges their static cell information.

	Add a predicate `remap_static_cell_references' which updates code using
	the second global_data structure (passed to merge_global_datas) to
	refer to static cells in the combined global_data structure.

compiler/layout_out.m:
compiler/llds.m:
compiler/llds_out.m:
compiler/opt_debug.m:
	Conform to the type change of common cell type numbers.

compiler/options.m:
doc/user_guide.texi:
	Add `--parallel-liveness' and `--parallel-code-gen' options.
	The documentation is commented out for now.

compiler/handle_options.m:
	Make the `--parallel-liveness' and `--parallel-code-gen' options imply
	`--no-trad-passes'.

compiler/liveness.m:
	Add parallel liveness detection support.

	The sequential liveness detection code took I/O states in order to
	output debugging information; make it take values of a typeclass
	`debug_liveness_io' instead, and make io.state an instance of the
	typeclass.  In the parallel case we pass dummy values that don't try to
	output debugging information.

compiler/mercury_compile.m:
	Run parallel liveness detection if it is enabled and liveness debugging
	is not enabled (see above).

compiler/proc_gen.m:
	Add parallel code generation support.  Run it if selected by the user
	and `--very-verbose' is not enabled (as that would require I/O).

runtime/mercury_context.c:
	Clear the detstack and nondetstack of a MR_Context structure when it is
	destroyed (put back on the free list) to speed up conservative garbage
	collection, and to unnecessary retention of memory.


Index: compiler/global_data.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/global_data.m,v
retrieving revision 1.21
diff -u -r1.21 global_data.m
--- compiler/global_data.m	31 Jul 2006 08:31:38 -0000	1.21
+++ compiler/global_data.m	9 Aug 2006 05:22:41 -0000
@@ -100,6 +100,33 @@
 :- pred rval_type_as_arg(rval::in, exprn_opts::in, llds_type::out) is det.
 
 %-----------------------------------------------------------------------------%
+
+:- type static_cell_remap_info.
+
+    % bump_type_num_counter(GlobalData, Increment)
+    %
+    % Return a copy of GlobalData with a type counter incremented by Increment.
+    %
+:- func bump_type_num_counter(global_data, int) = global_data.
+
+    % merge_global_datas(GlobalDataA, GlobalDataB, GlobalData, Remap)
+    %
+    % Merge two global data structures, where static cell information from
+    % GlobalDataA takes precedence over GlobalDataB.  The type numbers of the
+    % two global_data structures must be distinct.  Remap contains the
+    % information necessary for remap_static_cell_references/3.
+    %
+:- pred merge_global_datas(global_data::in, global_data::in, global_data::out,
+    static_cell_remap_info::out) is det.
+
+    % Update instructions in a C procedure that reference the static cells
+    % from the GlobalDataB that was passed to merge_global_datas/4, to
+    % reference the static cells of the merged global_data structure.
+    %
+:- pred remap_static_cell_references(static_cell_remap_info::in,
+    c_procedure::in, c_procedure::out) is det.
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- implementation.
@@ -116,6 +143,8 @@
 :- import_module pair.
 :- import_module require.
 :- import_module set.
+:- import_module svbimap.
+:- import_module svmap.
 
 %-----------------------------------------------------------------------------%
 
@@ -242,17 +271,17 @@
 
 :- type static_cell_info
     --->    static_cell_info(
-                sub_info                    :: static_cell_sub_info,
-                type_counter                :: counter, % next type number
+                sub_info                :: static_cell_sub_info,
+                type_counter            :: counter, % next type number
 
                 % Maps types to type numbers and vice versa.
-                cell_type_num_map           :: bimap(common_cell_type, int),
+                cell_type_num_map       :: bimap(common_cell_type, type_num),
 
                 % Maps the cell type number to the information we have
                 % for all scalar cells of that type.
-                scalar_cell_group_map       :: map(int, scalar_cell_group),
+                scalar_cell_group_map   :: map(type_num, scalar_cell_group),
 
-                vector_cell_group_map       :: map(int, vector_cell_group)
+                vector_cell_group_map   :: map(type_num, vector_cell_group)
             ).
 
 init_static_cell_info(BaseName, UnboxFloat, CommonData) = Info0 :-
@@ -299,7 +328,8 @@
             )
         ;
             TypeNumCounter0 = !.Info ^ type_counter,
-            counter.allocate(TypeNum, TypeNumCounter0, TypeNumCounter),
+            counter.allocate(TypeNum0, TypeNumCounter0, TypeNumCounter),
+            TypeNum = type_num(TypeNum0),
             !:Info = !.Info ^ type_counter := TypeNumCounter,
 
             bimap.det_insert(TypeNumMap0, CellType, TypeNum, TypeNumMap),
@@ -428,7 +458,8 @@
             )
         ;
             TypeNumCounter0 = !.Info ^ type_counter,
-            counter.allocate(TypeNum, TypeNumCounter0, TypeNumCounter),
+            counter.allocate(TypeNum0, TypeNumCounter0, TypeNumCounter),
+            TypeNum = type_num(TypeNum0),
             !:Info = !.Info ^ type_counter := TypeNumCounter,
 
             bimap.det_insert(TypeNumMap0, CellType, TypeNum, TypeNumMap),
@@ -472,7 +503,7 @@
     list.reverse(RevVectorDatas, VectorDatas).
 
 :- pred add_scalar_static_cell_for_type(module_name::in,
-    bimap(common_cell_type, int)::in, int::in, scalar_cell_group::in,
+    bimap(common_cell_type, type_num)::in, type_num::in, scalar_cell_group::in,
     list(scalar_common_data_array)::in, list(scalar_common_data_array)::out)
     is det.
 
@@ -485,7 +516,7 @@
     !:Arrays = [Array | !.Arrays].
 
 :- pred add_all_vector_static_cells_for_type(module_name::in,
-    bimap(common_cell_type, int)::in, int::in, vector_cell_group::in,
+    bimap(common_cell_type, type_num)::in, type_num::in, vector_cell_group::in,
     list(vector_common_data_array)::in, list(vector_common_data_array)::out)
     is det.
 
@@ -495,7 +526,7 @@
     map.foldl(add_one_vector_static_cell(ModuleName, TypeNum, CellType),
         CellGroup ^ vector_cell_map, !Arrays).
 
-:- pred add_one_vector_static_cell(module_name::in, int::in,
+:- pred add_one_vector_static_cell(module_name::in, type_num::in,
     common_cell_type::in, int::in, vector_contents::in,
     list(vector_common_data_array)::in, list(vector_common_data_array)::out)
     is det.
@@ -591,6 +622,474 @@
     natural_type(UnboxFloat, Rval, Type).
 
 %-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- type static_cell_remap_info
+    --->    static_cell_remap_info(
+                cell_type_num_remap,
+                map(type_num, scalar_cell_group_remap)
+                % A map from the _old_ type number, to the mapping of old
+                % data_names to new_data names.
+            ).
+
+:- type cell_type_num_remap     == map(type_num, type_num).
+                                    % Mapping of old to new type numbers.
+
+:- type scalar_cell_group_remap == map(data_name, data_name).
+                                    % Mapping of old to new data_names.
+
+bump_type_num_counter(GlobalData0, Increment) = GlobalData :-
+    Counter0 = GlobalData0 ^ static_cell_info ^ type_counter,
+    counter.allocate(N, Counter0, _),
+    Counter = counter.init(N + Increment),
+    GlobalData = GlobalData0 ^ static_cell_info ^ type_counter := Counter.
+
+merge_global_datas(GlobalDataA, GlobalDataB, GlobalData, Remap) :-
+    GlobalDataA = global_data(ProcVarMapA, ProcLayoutMapA, ClosureLayoutsA,
+        StaticCellInfoA),
+    GlobalDataB = global_data(ProcVarMapB, ProcLayoutMapB, ClosureLayoutsB,
+        StaticCellInfoB),
+    GlobalData = global_data(ProcVarMap, ProcLayoutMap, ClosureLayouts,
+        StaticCellInfo),
+    ProcVarMap = map.merge(ProcVarMapA, ProcVarMapB),
+    ProcLayoutMap = map.merge(ProcLayoutMapA, ProcLayoutMapB),
+    ClosureLayouts = ClosureLayoutsA ++ ClosureLayoutsB,
+    merge_static_cell_infos(StaticCellInfoA, StaticCellInfoB, StaticCellInfo,
+        Remap).
+
+:- pred merge_static_cell_infos(static_cell_info::in, static_cell_info::in,
+    static_cell_info::out, static_cell_remap_info::out) is det.
+
+merge_static_cell_infos(SCIa, SCIb, SCI, Remap) :-
+    SCIa = static_cell_info(SubInfoA, TypeCounterA,
+        CellTypeNumMapA, ScalarCellGroupMapA, VectorCellGroupMapA),
+    SCIb = static_cell_info(SubInfoB, _TypeCounterB,
+        CellTypeNumMapB, ScalarCellGroupMapB, VectorCellGroupMapB),
+    expect(unify(SubInfoA, SubInfoB), this_file, "merge_static_cell_info"),
+
+    % Merge cell type number maps.
+    bimap.foldl3(merge_cell_type_num_maps, CellTypeNumMapB,
+        TypeCounterA, TypeCounter, CellTypeNumMapA, CellTypeNumMap,
+        map.init, CellTypeNumMapRemap),
+
+    % Merge the scalar and vector cell group maps.
+    merge_scalar_cell_group_maps(CellTypeNumMapRemap,
+        ScalarCellGroupMapA, ScalarCellGroupMapB,
+        ScalarCellGroupMap, ScalarCellGroupRemap),
+    merge_vector_cell_group_maps(CellTypeNumMapRemap,
+        VectorCellGroupMapA, VectorCellGroupMapB,
+        VectorCellGroupMap),
+
+    Remap = static_cell_remap_info(CellTypeNumMapRemap, ScalarCellGroupRemap),
+
+    % Remap the information in the static_cell_info info itself.
+    SCI0 = static_cell_info(SubInfoA, TypeCounter,
+        CellTypeNumMap, ScalarCellGroupMap, VectorCellGroupMap),
+    SCI = remap_static_cell_info(Remap, SCI0).
+
+:- pred merge_cell_type_num_maps(common_cell_type::in, type_num::in,
+    counter::in, counter::out, bimap(common_cell_type, type_num)::in,
+    bimap(common_cell_type, type_num)::out,
+    cell_type_num_remap::in, cell_type_num_remap::out) is det.
+
+merge_cell_type_num_maps(CellType, BTypeNum,
+        !TypeCounter, !CellTypeNumMap, !TypeNumRemap) :-
+    (if bimap.search(!.CellTypeNumMap, CellType, ATypeNum) then
+        % A type also in GlobalDataA.
+        svmap.det_insert(BTypeNum, ATypeNum, !TypeNumRemap)
+    else
+        % A type not in GlobalDataA.
+        counter.allocate(N, !TypeCounter),
+        NewTypeNum = type_num(N),
+        svmap.det_insert(BTypeNum, NewTypeNum, !TypeNumRemap),
+        svbimap.det_insert(CellType, NewTypeNum, !CellTypeNumMap)
+    ).
+
+:- pred merge_scalar_cell_group_maps(cell_type_num_remap::in,
+    map(type_num, scalar_cell_group)::in, map(type_num, scalar_cell_group)::in,
+    map(type_num, scalar_cell_group)::out,
+    map(type_num, scalar_cell_group_remap)::out) is det.
+
+merge_scalar_cell_group_maps(TypeNumRemap,
+        ScalarCellGroupMapA, ScalarCellGroupMapB,
+        ScalarCellGroupMap, ScalarCellGroupRemap) :-
+    map.foldl2(merge_scalar_cell_group_maps_2(TypeNumRemap),
+        ScalarCellGroupMapB,
+        ScalarCellGroupMapA, ScalarCellGroupMap,
+        map.init, ScalarCellGroupRemap).
+
+:- pred merge_scalar_cell_group_maps_2(cell_type_num_remap::in,
+    type_num::in, scalar_cell_group::in,
+    map(type_num, scalar_cell_group)::in,
+    map(type_num, scalar_cell_group)::out,
+    map(type_num, scalar_cell_group_remap)::in,
+    map(type_num, scalar_cell_group_remap)::out) is det.
+
+merge_scalar_cell_group_maps_2(TypeNumRemap, BTypeNum, BScalarCellGroup,
+        !ScalarCellGroupMap, !Remap) :-
+    map.lookup(TypeNumRemap, BTypeNum, TypeNum),
+    (if
+        ScalarCellGroupPrime = !.ScalarCellGroupMap ^ elem(TypeNum)
+    then
+        ScalarCellGroup0 = ScalarCellGroupPrime
+    else
+        % Could do this more efficiently.
+        ScalarCellGroup0 = scalar_cell_group(counter.init(0), bimap.init, [])
+    ),
+    merge_scalar_cell_groups(TypeNum, ScalarCellGroup0, BScalarCellGroup,
+        ScalarCellGroup, ScalarCellGroupRemap),
+    svmap.set(TypeNum, ScalarCellGroup, !ScalarCellGroupMap),
+    svmap.det_insert(BTypeNum, ScalarCellGroupRemap, !Remap).
+
+:- pred merge_scalar_cell_groups(type_num::in,
+    scalar_cell_group::in, scalar_cell_group::in, scalar_cell_group::out,
+    scalar_cell_group_remap::out) is det.
+
+merge_scalar_cell_groups(TypeNum, GroupA, GroupB, GroupAB, GroupRemap) :-
+    GroupA  = scalar_cell_group(_CounterA, GroupMembersA,  RevArrayA),
+    GroupB  = scalar_cell_group(_CounterB, GroupMembersB,  RevArrayB),
+    GroupAB = scalar_cell_group(CounterAB, GroupMembersAB, RevArrayAB),
+
+    CounterAB = counter.init(length(RevArrayAB)),
+
+    ArrayA  = reverse(RevArrayA),
+    ArrayB  = reverse(RevArrayB),
+    ArrayAB = ArrayA ++ delete_elems(ArrayB, ArrayA),
+    RevArrayAB = reverse(ArrayAB),
+
+    bimap.foldl2(merge_scalar_cell_groups_2(TypeNum, ArrayB, ArrayAB),
+        GroupMembersB,
+        GroupMembersA, GroupMembersAB, map.init, GroupRemap).
+
+:- pred merge_scalar_cell_groups_2(type_num::in,
+    list(common_cell_value)::in, list(common_cell_value)::in, 
+    list(rval)::in, data_name::in,
+    bimap(list(rval), data_name)::in, bimap(list(rval), data_name)::out,
+    scalar_cell_group_remap::in, scalar_cell_group_remap::out) is det.
+
+merge_scalar_cell_groups_2(TypeNum, ArrayB, ArrayAB,
+        Rvals, BDataName, !GroupMembers, !GroupRemap) :-
+    (if
+        bimap.search(!.GroupMembers, Rvals, DataName)
+    then
+        % Seen this list of rvals before in the group.
+        svmap.det_insert(BDataName, DataName, !GroupRemap)
+    else
+        % Not seen this list of rvals before in the group.
+        (
+            BDataName = scalar_common_ref(_, BCellNum),
+            % Look up what value this cell number referred to in the B array.
+            % Find the cell number of the same value in the combined A+B array.
+            CommonCellValue = list.det_index0(ArrayB, BCellNum),
+            CellNum = nth_member_lookup0(ArrayAB, CommonCellValue),
+            % Add the new data name.
+            DataName = scalar_common_ref(TypeNum, CellNum),
+            svbimap.det_insert(Rvals, DataName, !GroupMembers),
+            svmap.det_insert(BDataName, DataName, !GroupRemap)
+        ;
+            ( BDataName = vector_common_ref(_, _)
+            ; BDataName = proc_tabling_ref(_, _)
+            ),
+            unexpected(this_file, "merge_scalar_cell_groups_2")
+        )
+    ).
+
+:- pred merge_vector_cell_group_maps(cell_type_num_remap::in,
+    map(type_num, vector_cell_group)::in, map(type_num, vector_cell_group)::in,
+    map(type_num, vector_cell_group)::out) is det.
+
+merge_vector_cell_group_maps(TypeNumRemap, VectorCellGroupMapA,
+        VectorCellGroupMapB, VectorCellGroupMap) :-
+    map.foldl(merge_vector_cell_group_maps_2(TypeNumRemap),
+        VectorCellGroupMapB,
+        VectorCellGroupMapA, VectorCellGroupMap).
+
+:- pred merge_vector_cell_group_maps_2(cell_type_num_remap::in,
+    type_num::in, vector_cell_group::in, map(type_num, vector_cell_group)::in,
+    map(type_num, vector_cell_group)::out) is det.
+
+merge_vector_cell_group_maps_2(TypeNumRemap, OldTypeNum, VectorCellGroup,
+        !VectorCellGroupMap) :-
+    NewTypeNum = TypeNumRemap ^ det_elem(OldTypeNum),
+    svmap.det_insert(NewTypeNum, VectorCellGroup, !VectorCellGroupMap).
+
+:- func nth_member_lookup0(list(T), T) = int.
+
+nth_member_lookup0(List, Elem) = Pos-1 :-
+    list.nth_member_lookup(List, Elem, Pos).
+
+%-----------------------------------------------------------------------------%
+
+    % The scalar cell group and vector cell group contents themselves
+    % need to be updated to use the merged cell information.
+    %
+:- func remap_static_cell_info(static_cell_remap_info,
+    static_cell_info) = static_cell_info.
+
+remap_static_cell_info(Remap, SCI0) = SCI :-
+    ScalarMap = map.map_values(remap_scalar_cell_group(Remap),
+        SCI0 ^ scalar_cell_group_map),
+    VectorMap = map.map_values(remap_vector_cell_group(Remap),
+        SCI0 ^ vector_cell_group_map),
+    SCI = (SCI0 ^ scalar_cell_group_map := ScalarMap)
+                ^ vector_cell_group_map := VectorMap.
+
+:- func remap_scalar_cell_group(static_cell_remap_info,
+    type_num, scalar_cell_group) = scalar_cell_group.
+
+remap_scalar_cell_group(Remap, _, ScalarCellGroup0) = ScalarCellGroup :-
+    Array0 = ScalarCellGroup0 ^ scalar_cell_rev_array,
+    Array  = list.map(remap_common_cell_value(Remap), Array0),
+    ScalarCellGroup = ScalarCellGroup0 ^ scalar_cell_rev_array := Array.
+
+:- func remap_vector_cell_group(static_cell_remap_info,
+    type_num, vector_cell_group) = vector_cell_group.
+
+remap_vector_cell_group(Remap, _, VectorCellGroup0) = VectorCellGroup :-
+    VectorCellGroup0 = vector_cell_group(Counter, Map0),
+    VectorCellGroup  = vector_cell_group(Counter, Map),
+    Map = map.map_values(remap_vector_contents(Remap), Map0).
+
+:- func remap_vector_contents(static_cell_remap_info,
+    int, vector_contents) = vector_contents.
+
+remap_vector_contents(Remap, _, Contents0) = Contents :-
+    Contents0 = vector_contents(Values0),
+    Contents  = vector_contents(Values),
+    Values = list.map(remap_common_cell_value(Remap), Values0).
+
+:- func remap_common_cell_value(static_cell_remap_info,
+    common_cell_value) = common_cell_value.
+
+remap_common_cell_value(Remap, CommonCellValue0) = CommonCellValue :-
+    (
+        CommonCellValue0 = plain_value(RvalsTypes0),
+        CommonCellValue  = plain_value(RvalsTypes),
+        RvalsTypes = list.map(remap_plain_value(Remap), RvalsTypes0)
+    ;
+        CommonCellValue0 = grouped_args_value(ArgGroup0),
+        CommonCellValue  = grouped_args_value(ArgGroup),
+        ArgGroup = list.map(remap_arg_group_value(Remap), ArgGroup0)
+    ).
+
+:- func remap_plain_value(static_cell_remap_info,
+    pair(rval, llds_type)) = pair(rval, llds_type).
+
+remap_plain_value(Remap, Rval0 - Type) = Rval - Type :-
+    Rval = remap_rval(Remap, Rval0).
+
+:- func remap_arg_group_value(static_cell_remap_info,
+    common_cell_arg_group) = common_cell_arg_group.
+
+remap_arg_group_value(Remap, GroupedArgs0) = GroupedArgs :-
+    (
+        GroupedArgs0 = common_cell_grouped_args(Type, Fields, Rvals0),
+        GroupedArgs  = common_cell_grouped_args(Type, Fields, Rvals),
+        Rvals = list.map(remap_rval(Remap), Rvals0)
+    ;
+        GroupedArgs0 = common_cell_ungrouped_arg(Type, Rvals0),
+        GroupedArgs  = common_cell_ungrouped_arg(Type, Rvals),
+        Rvals = remap_rval(Remap, Rvals0)
+    ).
+
+%-----------------------------------------------------------------------------%
+
+remap_static_cell_references(Remap, Procedure0, Procedure) :-
+    Code0 = Procedure0 ^ cproc_code,
+    Code  = list.map(remap_instruction(Remap), Code0),
+    Procedure = Procedure0 ^ cproc_code := Code.
+
+:- func remap_instruction(static_cell_remap_info, instruction) = instruction.
+
+remap_instruction(Remap, Instr0 - Comment)
+    = remap_instr(Remap, Instr0) - Comment.
+
+:- func remap_instr(static_cell_remap_info, instr) = instr.
+
+remap_instr(Remap, Instr0) = Instr :-
+    (
+        Instr0 = block(NumIntTemps, NumFloatTemps, Block0),
+        Instr  = block(NumIntTemps, NumFloatTemps, Block),
+        Block  = list.map(remap_instruction(Remap), Block0)
+    ;
+        Instr0 = assign(Lval, Rval0),
+        Instr  = assign(Lval, Rval),
+        Rval = remap_rval(Remap, Rval0)
+    ;
+        Instr0 = if_val(Rval0, CodeAddr),
+        Instr  = if_val(Rval, CodeAddr),
+        Rval = remap_rval(Remap, Rval0)
+    ;
+        ( Instr0 = comment(_)
+        ; Instr0 = livevals(_)
+        ; Instr0 = llcall(_, _, _, _, _, _)
+        ; Instr0 = mkframe(_, _)
+        ; Instr0 = label(_)
+        ; Instr0 = goto(_)
+        ; Instr0 = computed_goto(_, _)
+        ; Instr0 = arbitrary_c_code(_, _)
+        ; Instr0 = save_maxfr(_)
+        ; Instr0 = restore_maxfr(_)
+        ; Instr0 = incr_hp(_, _, _, _, _)
+        ; Instr0 = mark_hp(_)
+        ; Instr0 = restore_hp(_)
+        ; Instr0 = free_heap(_)
+        ; Instr0 = store_ticket(_)
+        ; Instr0 = reset_ticket(_, _)
+        ; Instr0 = prune_ticket
+        ; Instr0 = discard_ticket
+        ; Instr0 = mark_ticket_stack(_)
+        ; Instr0 = prune_tickets_to(_)
+        ; Instr0 = incr_sp(_, _)
+        ; Instr0 = decr_sp(_)
+        ; Instr0 = decr_sp_and_return(_)
+        ; Instr0 = pragma_c(_, _, _, _, _, _, _, _, _)
+        ; Instr0 = init_sync_term(_, _)
+        ; Instr0 = fork(_, _, _)
+        ; Instr0 = join_and_terminate(_)
+        ; Instr0 = join_and_continue(_, _)
+        ),
+        Instr = Instr0
+    ).
+
+:- func remap_lval(static_cell_remap_info, lval) = lval.
+
+remap_lval(Remap, Lval0) = Lval :-
+    (
+        Lval0 = field(MaybeTag, Rval0, FieldNum),
+        Lval  = field(MaybeTag, Rval, FieldNum),
+        Rval  = remap_rval(Remap, Rval0)
+    ;
+        Lval0 = mem_ref(Rval0),
+        Lval  = mem_ref(Rval),
+        Rval  = remap_rval(Remap, Rval0)
+    ;
+        ( Lval0 = reg(_, _)
+        ; Lval0 = succip
+        ; Lval0 = maxfr
+        ; Lval0 = curfr
+        ; Lval0 = hp
+        ; Lval0 = sp
+        ; Lval0 = temp(_, _)
+        ; Lval0 = stackvar(_)
+        ; Lval0 = framevar(_)
+        ; Lval0 = succip_slot(_)
+        ; Lval0 = redoip_slot(_)
+        ; Lval0 = redofr_slot(_)
+        ; Lval0 = succfr_slot(_)
+        ; Lval0 = prevfr_slot(_)
+        ; Lval0 = global_var_ref(_)
+        ; Lval0 = lvar(_)
+        ),
+        Lval = Lval0
+    ).
+
+:- func remap_rval(static_cell_remap_info, rval) = rval.
+
+remap_rval(Remap, Rval0) = Rval :-
+    (
+        Rval0 = lval(Lval0),
+        Rval  = lval(Lval),
+        Lval  = remap_lval(Remap, Lval0)
+    ;
+        Rval0 = var(_),
+        Rval  = Rval0
+    ;
+        Rval0 = mkword(Tag, Ptr0),
+        Rval  = mkword(Tag, Ptr),
+        Ptr   = remap_rval(Remap, Ptr0)
+    ;
+        Rval0 = const(Const0),
+        Rval  = const(Const),
+        Const = remap_rval_const(Remap, Const0)
+    ;
+        Rval0 = unop(Unop, A0),
+        Rval  = unop(Unop, A),
+        A = remap_rval(Remap, A0)
+    ;
+        Rval0 = binop(Binop, A0, B0),
+        Rval  = binop(Binop, A, B),
+        A = remap_rval(Remap, A0),
+        B = remap_rval(Remap, B0)
+    ;
+        Rval0 = mem_addr(MemRef0),
+        Rval  = mem_addr(MemRef),
+        MemRef = remap_mem_ref(Remap, MemRef0)
+    ).
+
+:- func remap_rval_const(static_cell_remap_info, rval_const) = rval_const.
+
+remap_rval_const(Remap, Const0) = Const :-
+    (
+        Const0 = data_addr_const(Addr0, MaybeOffset),
+        Const  = data_addr_const(Addr,  MaybeOffset),
+        (
+            Addr0 = data_addr(ModuleName, DataName0),
+            Addr  = data_addr(ModuleName, DataName),
+            DataName = remap_data_name(Remap, DataName0)
+        ;
+            Addr0 = rtti_addr(_),
+            Addr = Addr0
+        ;
+            Addr0 = layout_addr(_),
+            Addr = Addr0
+        )
+    ;
+        ( Const0 = true
+        ; Const0 = false
+        ; Const0 = int_const(_)
+        ; Const0 = float_const(_)
+        ; Const0 = string_const(_)
+        ; Const0 = multi_string_const(_, _)
+        ; Const0 = code_addr_const(_)
+        ),
+        Const = Const0
+    ).
+
+:- func remap_data_name(static_cell_remap_info, data_name) = data_name.
+
+remap_data_name(Remap, DataName0) = DataName :-
+    Remap = static_cell_remap_info(TypeNumRemap, ScalarCellGroupRemap),
+    (
+        DataName0 = scalar_common_ref(TypeNum0, _Offset),
+        (if
+            map.contains(TypeNumRemap, TypeNum0)
+        then
+            DataName = ScalarCellGroupRemap ^ det_elem(TypeNum0)
+                                            ^ det_elem(DataName0)
+        else
+            DataName = DataName0
+        )
+    ;
+        DataName0 = vector_common_ref(TypeNum0, Offset),
+        (if
+            map.search(TypeNumRemap, TypeNum0, TypeNum)
+        then
+            DataName = vector_common_ref(TypeNum, Offset)
+        else
+            DataName = DataName0
+        )
+    ;
+        DataName0 = proc_tabling_ref(_, _),
+        DataName = DataName0
+    ).
+
+:- func remap_mem_ref(static_cell_remap_info, mem_ref) = mem_ref.
+
+remap_mem_ref(Remap, MemRef0) = MemRef :-
+    (
+        MemRef0 = stackvar_ref(_),
+        MemRef = MemRef0
+    ;
+        MemRef0 = framevar_ref(_),
+        MemRef = MemRef0
+    ;
+        MemRef0 = heap_ref(Ptr0, Tag, FieldNum),
+        MemRef  = heap_ref(Ptr, Tag, FieldNum),
+        Ptr = remap_rval(Remap, Ptr0)
+    ).
+
+%-----------------------------------------------------------------------------%
 
 :- func this_file = string.
 
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.270
diff -u -r1.270 handle_options.m
--- compiler/handle_options.m	27 Jul 2006 05:01:05 -0000	1.270
+++ compiler/handle_options.m	9 Aug 2006 07:19:44 -0000
@@ -1383,11 +1383,18 @@
             true
         ),
 
-        % --dump-hlds and --statistics require compilation by phases
+        % --dump-hlds, --statistics, --parallel-liveness and
+        % --parallel-code-gen require compilation by phases
         globals.lookup_accumulating_option(!.Globals, dump_hlds, DumpStages),
+        globals.lookup_bool_option(!.Globals, parallel_liveness,
+            ParallelLiveness),
+        globals.lookup_bool_option(!.Globals, parallel_code_gen,
+            ParallelCodeGen),
         (
             ( DumpStages = [_ | _]
             ; Statistics = yes
+            ; ParallelLiveness = yes
+            ; ParallelCodeGen = yes
             )
         ->
             globals.set_option(trad_passes, bool(no), !Globals)
Index: compiler/layout_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/layout_out.m,v
retrieving revision 1.69
diff -u -r1.69 layout_out.m
--- compiler/layout_out.m	9 Aug 2006 03:17:14 -0000	1.69
+++ compiler/layout_out.m	9 Aug 2006 03:17:34 -0000
@@ -500,7 +500,7 @@
 
 :- type rval_or_numpair_or_none
     --->    rval(rval)
-    ;       num_pair(int, int)
+    ;       num_pair(type_num, int)
     ;       none.
 
 :- pred output_rval_or_numpair_or_none(rval_or_numpair_or_none::in,
@@ -509,7 +509,7 @@
 output_rval_or_numpair_or_none(rval(Rval), !IO) :-
     io.write_string(", ", !IO),
     output_rval_as_addr(Rval, !IO).
-output_rval_or_numpair_or_none(num_pair(Num1, Num2), !IO) :-
+output_rval_or_numpair_or_none(num_pair(type_num(Num1), Num2), !IO) :-
     io.write_string(", ", !IO),
     io.write_int(Num1, !IO),
     io.write_string(", ", !IO),
Index: compiler/liveness.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/liveness.m,v
retrieving revision 1.149
diff -u -r1.149 liveness.m
--- compiler/liveness.m	31 Jul 2006 08:31:45 -0000	1.149
+++ compiler/liveness.m	16 Aug 2006 04:56:36 -0000
@@ -166,6 +166,13 @@
 :- pred detect_liveness_proc(pred_id::in, proc_id::in, module_info::in,
     proc_info::in, proc_info::out, io::di, io::uo) is det.
 
+    % Add liveness annotations to the goals of nonimported procedures in the
+    % module.  Attempt to do so in parallel.  Debugging liveness is not
+    % supported in this version.
+    %
+:- pred detect_liveness_preds_parallel(module_info::in, module_info::out)
+    is det.
+
     % Return the set of variables live at the start of the procedure.
     %
 :- pred initial_liveness(proc_info::in, pred_id::in, module_info::in,
@@ -199,6 +206,7 @@
 
 :- import_module assoc_list.
 :- import_module bool.
+:- import_module int.
 :- import_module list.
 :- import_module map.
 :- import_module maybe.
@@ -206,11 +214,84 @@
 :- import_module string.
 :- import_module svset.
 :- import_module term.
+:- import_module unit.
 :- import_module varset.
 
 %-----------------------------------------------------------------------------%
 
+:- typeclass debug_liveness_io(T) where [
+    pred maybe_debug_liveness(string::in, int::in, int::in,
+        hlds_goal::in, prog_varset::in, module_info::in,
+        T::di, T::uo) is det
+].
+
+:- instance debug_liveness_io(io) where [
+    pred(maybe_debug_liveness/8) is io_maybe_debug_liveness
+].
+
+:- instance debug_liveness_io(unit) where [
+    maybe_debug_liveness(_, _, _, _, _, _, unit, unit)
+].
+
+%-----------------------------------------------------------------------------%
+
+detect_liveness_preds_parallel(!HLDS) :-
+    module_info_predids(!.HLDS, PredIds),
+    interleave(PredIds, PredIdsA, PredIdsB, 0, Length),
+    (
+        % Rather arbitrary.
+        Length < 1000
+    ->
+        list.foldl(detect_liveness_pred_putback, PredIds, !HLDS)
+    ;
+        ( list.map(detect_liveness_pred(!.HLDS), PredIdsA, PredInfosA)
+        & list.foldl(detect_liveness_pred_putback, PredIdsB, !HLDS)
+        ),
+        list.foldl_corresponding(module_info_set_pred_info,
+            PredIdsA, PredInfosA, !HLDS)
+    ).
+
+:- pred interleave(list(T)::in, list(T)::out, list(T)::out, int::in, int::out)
+    is det.
+
+interleave([],    [],     [], Length, Length).
+interleave([H|T], [H|As], Bs, Length0, Length) :-
+    interleave(T, Bs, As, Length0+1, Length).
+
+:- pred detect_liveness_pred_putback(pred_id::in,
+    module_info::in, module_info::out) is det.
+
+detect_liveness_pred_putback(PredId, !HLDS) :-
+    detect_liveness_pred(!.HLDS, PredId, PredInfo),
+    module_info_set_pred_info(PredId, PredInfo, !HLDS).
+
+:- pred detect_liveness_pred(module_info::in, pred_id::in, pred_info::out)
+    is det.
+
+detect_liveness_pred(ModuleInfo, PredId, PredInfo) :-
+    module_info_pred_info(ModuleInfo, PredId, PredInfo0),
+    ProcIds = pred_info_non_imported_procids(PredInfo0),
+    list.foldl(detect_liveness_pred_proc(ModuleInfo, PredId), ProcIds,
+        PredInfo0, PredInfo).
+
+:- pred detect_liveness_pred_proc(module_info::in, pred_id::in,
+    proc_id::in, pred_info::in, pred_info::out) is det.
+
+detect_liveness_pred_proc(ModuleInfo, PredId, ProcId, !PredInfo) :-
+    pred_info_proc_info(!.PredInfo, ProcId, ProcInfo0),
+    detect_liveness_proc_2(PredId, ModuleInfo, ProcInfo0, ProcInfo, unit, _),
+    pred_info_set_proc_info(ProcId, ProcInfo, !PredInfo).
+
+%-----------------------------------------------------------------------------%
+
 detect_liveness_proc(PredId, _ProcId, ModuleInfo, !ProcInfo, !IO) :-
+    detect_liveness_proc_2(PredId, ModuleInfo, !ProcInfo, !IO).
+
+:- pred detect_liveness_proc_2(pred_id::in, module_info::in,
+    proc_info::in, proc_info::out, IO::di, IO::uo) is det
+    <= debug_liveness_io(IO).
+
+detect_liveness_proc_2(PredId, ModuleInfo, !ProcInfo, !IO) :-
     requantify_proc(!ProcInfo),
 
     proc_info_get_goal(!.ProcInfo, Goal0),
@@ -225,18 +306,18 @@
 
     globals.lookup_int_option(Globals, debug_liveness, DebugLiveness),
     pred_id_to_int(PredId, PredIdInt),
-    maybe_write_progress_message("\nbefore liveness",
+    maybe_debug_liveness("\nbefore liveness",
         DebugLiveness, PredIdInt, Goal0, VarSet, ModuleInfo, !IO),
 
     initial_liveness(!.ProcInfo, PredId, ModuleInfo, Liveness0),
     detect_liveness_in_goal(Goal0, Goal1, Liveness0, _, LiveInfo),
 
-    maybe_write_progress_message("\nafter liveness",
+    maybe_debug_liveness("\nafter liveness",
         DebugLiveness, PredIdInt, Goal1, VarSet, ModuleInfo, !IO),
 
     initial_deadness(!.ProcInfo, LiveInfo, ModuleInfo, Deadness0),
     detect_deadness_in_goal(Goal1, Goal2, Deadness0, _, Liveness0, LiveInfo),
-    maybe_write_progress_message("\nafter deadness",
+    maybe_debug_liveness("\nafter deadness",
         DebugLiveness, PredIdInt, Goal2, VarSet, ModuleInfo, !IO),
 
     (
@@ -247,7 +328,7 @@
         DelayDeath = yes
     ->
         delay_death_proc_body(Goal2, Goal3, VarSet, Liveness0),
-        maybe_write_progress_message("\nafter delay death",
+        maybe_debug_liveness("\nafter delay death",
             DebugLiveness, PredIdInt, Goal3, VarSet, ModuleInfo, !IO)
     ;
         Goal3 = Goal2
@@ -261,16 +342,16 @@
     ),
     detect_resume_points_in_goal(Goal3, Goal, Liveness0, _,
         LiveInfo, ResumeVars0),
-    maybe_write_progress_message("\nafter resume point",
+    maybe_debug_liveness("\nafter resume point",
         DebugLiveness, PredIdInt, Goal, VarSet, ModuleInfo, !IO),
     proc_info_set_goal(Goal, !ProcInfo),
     proc_info_set_liveness_info(Liveness0, !ProcInfo).
 
-:- pred maybe_write_progress_message(string::in, int::in, int::in,
+:- pred io_maybe_debug_liveness(string::in, int::in, int::in,
     hlds_goal::in, prog_varset::in, module_info::in,
     io::di, io::uo) is det.
 
-maybe_write_progress_message(Message, DebugLiveness, PredIdInt,
+io_maybe_debug_liveness(Message, DebugLiveness, PredIdInt,
         Goal, VarSet, ModuleInfo, !IO) :-
     ( DebugLiveness = PredIdInt ->
         io.write_string(Message, !IO),
Index: compiler/llds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds.m,v
retrieving revision 1.335
diff -u -r1.335 llds.m
--- compiler/llds.m	28 Jul 2006 05:08:09 -0000	1.335
+++ compiler/llds.m	3 Aug 2006 06:27:36 -0000
@@ -131,13 +131,16 @@
                 rval            % The field value.
             ).
 
+:- type type_num
+    --->    type_num(int).
+
 :- type scalar_common_data_array
     --->    scalar_common_data_array(
                 scda_module     :: module_name,
                                 % The basename of this C file.
                 scda_rval_types :: common_cell_type,
                                 % The type of the elements of the array.
-                scda_type_num   :: int,
+                scda_type_num   :: type_num,
                                 % The type number.
                 scda_values     :: list(common_cell_value)
                                 % The array elements, starting at offset 0.
@@ -149,7 +152,7 @@
                                 % The basename of this C file.
                 vcda_rval_types :: common_cell_type,
                                 % The type of the elements of the array.
-                vcda_type_num   :: int,
+                vcda_type_num   :: type_num,
                                 % The type number.
                 vcda_vector_num :: int,
                                 % The number of this vector, among all the
@@ -899,7 +902,7 @@
     ;       layout_addr(layout_name).
 
 :- type data_name
-    --->    scalar_common_ref(int, int)
+    --->    scalar_common_ref(type_num, int)
             % We store all standalone (scalar) common cells of the same type
             % in an array. A reference to one of these cells contains the
             % the type number (which becomes the distinguishing part of the
@@ -907,7 +910,7 @@
             % which is stored in the first integer, and the offset within
             % this array, which is stored in the second integer.
 
-    ;       vector_common_ref(int, int)
+    ;       vector_common_ref(type_num, int)
             % We store each vector of common cells in its own global variable,
             % identified by a sequence number. The first integer is this
             % sequence number; the second is the offset in the array.
Index: compiler/llds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds_out.m,v
retrieving revision 1.286
diff -u -r1.286 llds_out.m
--- compiler/llds_out.m	31 Jul 2006 08:31:45 -0000	1.286
+++ compiler/llds_out.m	3 Aug 2006 06:27:36 -0000
@@ -133,8 +133,8 @@
     % to put these in a new module (maybe llds_out_util).
 
 :- type decl_id
-    --->    decl_common_type(int)
-    ;       decl_scalar_common_array(int)
+    --->    decl_common_type(type_num)
+    ;       decl_scalar_common_array(type_num)
     ;       decl_float_label(string)
     ;       decl_code_addr(code_addr)
     ;       decl_data_addr(data_addr)
@@ -1160,7 +1160,7 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred output_common_type_defn(int::in, common_cell_type::in,
+:- pred output_common_type_defn(type_num::in, common_cell_type::in,
     decl_set::in, decl_set::out, io::di, io::uo) is det.
 
 output_common_type_defn(TypeNum, CellType, !DeclSet, !IO) :-
@@ -4258,22 +4258,23 @@
     mercury_var_prefix ++ "_proc" ++ tabling_info_id_str(Id) ++ "__" ++
         proc_label_to_c_string(ProcLabel, no).
 
-:- pred output_common_cell_type_name(int::in, io::di, io::uo) is det.
+:- pred output_common_cell_type_name(type_num::in, io::di, io::uo) is det.
 
-output_common_cell_type_name(TypeNum, !IO) :-
+output_common_cell_type_name(type_num(TypeNum), !IO) :-
     io.write_string(mercury_common_type_prefix, !IO),
     io.write_int(TypeNum, !IO).
 
-:- pred output_common_scalar_cell_array_name(int::in, io::di, io::uo) is det.
+:- pred output_common_scalar_cell_array_name(type_num::in, io::di, io::uo)
+    is det.
 
-output_common_scalar_cell_array_name(TypeNum, !IO) :-
+output_common_scalar_cell_array_name(type_num(TypeNum), !IO) :-
     io.write_string(mercury_scalar_common_array_prefix, !IO),
     io.write_int(TypeNum, !IO).
 
-:- pred output_common_vector_cell_array_name(int::in, int::in, io::di, io::uo)
-    is det.
+:- pred output_common_vector_cell_array_name(type_num::in, int::in,
+    io::di, io::uo) is det.
 
-output_common_vector_cell_array_name(TypeNum, CellNum, !IO) :-
+output_common_vector_cell_array_name(type_num(TypeNum), CellNum, !IO) :-
     io.write_string(mercury_vector_common_array_prefix, !IO),
     io.write_int(TypeNum, !IO),
     io.write_string("_", !IO),
@@ -4805,7 +4806,7 @@
     (
         Exprn = const(data_addr_const(DataAddr, no)),
         DataAddr = data_addr(_, DataName),
-        DataName = scalar_common_ref(TypeNum, CellNum)
+        DataName = scalar_common_ref(type_num(TypeNum), CellNum)
     ->
         io.write_string("MR_TAG_COMMON(", !IO),
         io.write_int(Tag, !IO),
@@ -4931,7 +4932,7 @@
         % very substantial.
         (
             DataAddr = data_addr(_, DataName),
-            DataName = scalar_common_ref(TypeNum, CellNum)
+            DataName = scalar_common_ref(type_num(TypeNum), CellNum)
         ->
             io.write_string("MR_COMMON(", !IO),
             io.write_int(TypeNum, !IO),
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.396
diff -u -r1.396 mercury_compile.m
--- compiler/mercury_compile.m	9 Aug 2006 04:56:35 -0000	1.396
+++ compiler/mercury_compile.m	16 Aug 2006 03:09:33 -0000
@@ -3979,8 +3979,17 @@
 compute_liveness(Verbose, Stats, !HLDS, !IO) :-
     maybe_write_string(Verbose, "% Computing liveness...\n", !IO),
     maybe_flush_output(Verbose, !IO),
-    process_all_nonimported_procs(update_proc_io(detect_liveness_proc),
-        !HLDS, !IO),
+    globals.io_lookup_bool_option(parallel_liveness, ParallelLiveness, !IO),
+    globals.io_lookup_int_option(debug_liveness, DebugLiveness, !IO),
+    (
+        ParallelLiveness = yes,
+        DebugLiveness = -1
+    ->
+        detect_liveness_preds_parallel(!HLDS)
+    ;
+        process_all_nonimported_procs(update_proc_io(detect_liveness_proc),
+            !HLDS, !IO)
+    ),
     maybe_write_string(Verbose, "% done.\n", !IO),
     maybe_report_stats(Stats, !IO).
 
Index: compiler/opt_debug.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/opt_debug.m,v
retrieving revision 1.171
diff -u -r1.171 opt_debug.m
--- compiler/opt_debug.m	28 Jul 2006 05:08:14 -0000	1.171
+++ compiler/opt_debug.m	3 Aug 2006 06:27:37 -0000
@@ -347,10 +347,10 @@
 dump_data_addr(layout_addr(LayoutName)) =
     "layout_addr(" ++ dump_layout_name(LayoutName) ++ ")".
 
-dump_data_name(scalar_common_ref(TypeNum, Offset)) =
+dump_data_name(scalar_common_ref(type_num(TypeNum), Offset)) =
     "scalar_common_ref(" ++ int_to_string(TypeNum) ++ ", "
         ++ int_to_string(Offset) ++ ")".
-dump_data_name(vector_common_ref(TypeNum, Offset)) =
+dump_data_name(vector_common_ref(type_num(TypeNum), Offset)) =
     "vector_common_ref(" ++ int_to_string(TypeNum) ++ ", "
         ++ int_to_string(Offset) ++ ")".
 dump_data_name(proc_tabling_ref(ProcLabel, Id)) =
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.523
diff -u -r1.523 options.m
--- compiler/options.m	14 Aug 2006 03:31:31 -0000	1.523
+++ compiler/options.m	15 Aug 2006 06:10:30 -0000
@@ -431,6 +431,8 @@
     ;       low_level_debug
     ;       table_debug
     ;       trad_passes
+    ;       parallel_liveness
+    ;       parallel_code_gen
     ;       polymorphism
     ;       reclaim_heap_on_failure
     ;       reclaim_heap_on_semidet_failure
@@ -1103,6 +1105,8 @@
     low_level_debug                     -   bool(no),
     table_debug                         -   bool(no),
     trad_passes                         -   bool(yes),
+    parallel_liveness                   -   bool(no),
+    parallel_code_gen                   -   bool(no),
     polymorphism                        -   bool(yes),
     reclaim_heap_on_failure             -   bool_special,
     reclaim_heap_on_semidet_failure     -   bool(yes),
@@ -1816,6 +1820,8 @@
 long_option("table-debug",          table_debug).
 long_option("polymorphism",         polymorphism).
 long_option("trad-passes",          trad_passes).
+long_option("parallel-liveness",    parallel_liveness).
+long_option("parallel-code-gen",    parallel_code_gen).
 long_option("reclaim-heap-on-failure",  reclaim_heap_on_failure).
 long_option("reclaim-heap-on-semidet-failure",
                     reclaim_heap_on_semidet_failure).
@@ -3784,6 +3790,16 @@
         "\tThis option tells the compiler",
         "\tto complete each phase of code generation on all predicates",
         "\tbefore going on the next phase on all predicates.",
+    %   "--parallel-liveness",
+    %   "Use multiple threads when computing liveness.",
+    %   "At the moment this option implies `--no-trad-passes',",
+    %   "and requires the compiler to be built in a",
+    %   "low-level parallel grade and running with multiple engines.",
+    %   "--parallel-code-gen",
+    %   "Use multiple threads when generating code.",
+    %   "At the moment this option implies `--no-trad-passes',",
+    %   "and requires the compiler to be built in a",
+    %   "low-level parallel grade and running with multiple engines.",
     %   "\t--no-polymorphism",
     %   "\t\tDon't handle polymorphic types.",
     %   "\t\t(Generates slightly more efficient code, but stops",
Index: compiler/proc_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/proc_gen.m,v
retrieving revision 1.4
diff -u -r1.4 proc_gen.m
--- compiler/proc_gen.m	28 Jul 2006 05:08:14 -0000	1.4
+++ compiler/proc_gen.m	16 Aug 2006 05:04:47 -0000
@@ -117,34 +117,105 @@
 generate_code(ModuleInfo0, !GlobalData, Procedures, !IO) :-
     % Get a list of all the predicate ids for which we will generate code.
     module_info_predids(ModuleInfo0, PredIds),
-    % Now generate the code for each predicate.
-    generate_pred_list_code(ModuleInfo0, !GlobalData, PredIds,
-        Procedures, !IO).
-
-    % Translate a list of HLDS predicates to LLDS.
-    %
-:- pred generate_pred_list_code(module_info::in,
-    global_data::in, global_data::out,
-    list(pred_id)::in, list(c_procedure)::out, io::di, io::uo) is det.
-
-generate_pred_list_code(_ModuleInfo, !GlobalData, [], [], !IO).
-generate_pred_list_code(ModuleInfo, !GlobalData, [PredId | PredIds],
-        Predicates, !IO) :-
-    generate_maybe_pred_code(ModuleInfo, !GlobalData, PredId,
-        Predicates0, !IO),
-    generate_pred_list_code(ModuleInfo, !GlobalData, PredIds,
-        Predicates1, !IO),
-    list.append(Predicates0, Predicates1, Predicates).
+    % Check if we want to use parallel code generation.
+    module_info_get_globals(ModuleInfo0, Globals),
+    globals.lookup_bool_option(Globals, parallel_code_gen, ParallelCodeGen),
+    globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
+    globals.lookup_bool_option(Globals, detailed_statistics, Statistics),
+    (
+        ParallelCodeGen = yes,
+        % Can't do parallel code generation if I/O is required.
+        VeryVerbose = no,
+        Statistics = no
+    ->
+        generate_code_maybe_parallel(ModuleInfo0, PredIds, !GlobalData,
+            Procedures, !IO)
+    ;
+        generate_code_sequential(ModuleInfo0, PredIds, !GlobalData,
+            Procedures, !IO)
+    ).
+
+:- pred generate_code_sequential(module_info::in, list(pred_id)::in,
+    global_data::in, global_data::out, list(c_procedure)::out, io::di, io::uo)
+    is det.
+
+generate_code_sequential(ModuleInfo0, PredIds, !GlobalData, Procedures, !IO) :-
+    list.map_foldl2(generate_maybe_pred_code(ModuleInfo0),
+        PredIds, PredProcedures, !GlobalData, !IO),
+    list.condense(PredProcedures, Procedures).
+
+%-----------------------------------------------------------------------------%
+
+:- pred generate_code_maybe_parallel(module_info::in, list(pred_id)::in,
+    global_data::in, global_data::out, list(c_procedure)::out, io::di, io::uo)
+    is det.
+
+generate_code_maybe_parallel(ModuleInfo0, PredIds, !GlobalData, Procedures,
+        !IO) :-
+    list.length(PredIds, Len),
+    (if Len < min_parallel_preds then
+        generate_code_sequential(ModuleInfo0, PredIds, !GlobalData,
+            Procedures, !IO)
+    else
+        % Split up the list of predicates into pieces for processing in
+        % parallel.  Splitting the list in the middle does not work well as the
+        % load will be unbalanced.  However, splitting the list differently way
+        % does mean that the generated code will be slightly different, due to
+        % the static data being reordered.
+        list.chunk(PredIds, pred_list_chunk_size, ListOfLists),
+        interleave(ListOfLists, ListsOfPredIdsA, ListsOfPredIdsB),
+        (
+            list.condense(ListsOfPredIdsA, PredIdsA),
+            list.map_foldl(generate_pred_code_par(ModuleInfo0),
+                PredIdsA, PredProceduresA, !.GlobalData, GlobalDataA),
+            list.condense(PredProceduresA, ProceduresA)
+        &
+            list.condense(ListsOfPredIdsB, PredIdsB),
+            GlobalData1 = bump_type_num_counter(!.GlobalData, type_num_skip),
+            list.map_foldl(generate_pred_code_par(ModuleInfo0),
+                PredIdsB, PredProceduresB0, GlobalData1, GlobalDataB),
+            list.condense(PredProceduresB0, ProceduresB0)
+        ),
+        merge_global_datas(GlobalDataA, GlobalDataB, !:GlobalData,
+            StaticCellRemapInfo),
+        list.map(remap_static_cell_references(StaticCellRemapInfo),
+            ProceduresB0, ProceduresB),
+        Procedures = ProceduresA ++ ProceduresB
+    ).
+
+    % These numbers are all rather arbitrary.
+    %
+:- func min_parallel_preds = int.
+min_parallel_preds = 400.
+
+:- func pred_list_chunk_size = int.
+pred_list_chunk_size = 50.
+
+:- func type_num_skip = int.
+type_num_skip = 10000.
+
+:- pred interleave(list(T)::in, list(T)::out, list(T)::out) is det.
+:- pred interleave_2(list(T)::in, list(T)::in, list(T)::out,
+    list(T)::in, list(T)::out) is det.
+
+interleave(L, reverse(As), reverse(Bs)) :-
+    interleave_2(L, [], As, [], Bs).
+
+interleave_2([], !As, !Bs).
+interleave_2([H|T], As0, As, Bs0, Bs) :-
+    interleave_2(T, Bs0, Bs, [H|As0], As).
+
+%-----------------------------------------------------------------------------%
 
 :- pred generate_maybe_pred_code(module_info::in,
-    global_data::in, global_data::out, pred_id::in,
-    list(c_procedure)::out, io::di, io::uo) is det.
+    pred_id::in, list(c_procedure)::out,
+    global_data::in, global_data::out, io::di, io::uo) is det.
 
     % Note that some of the logic of generate_maybe_pred_code is duplicated
     % by mercury_compile.backend_pass_by_preds, so modifications here may
     % also need to be repeated there.
     %
-generate_maybe_pred_code(ModuleInfo, !GlobalData, PredId, Predicates, !IO) :-
+generate_maybe_pred_code(ModuleInfo, PredId, Predicates, !GlobalData, !IO) :-
     module_info_preds(ModuleInfo, PredInfos),
     map.lookup(PredInfos, PredId, PredInfo),
     ProcIds = pred_info_non_imported_procids(PredInfo),
@@ -170,6 +241,16 @@
             PredId, PredInfo, ProcIds, Predicates)
     ).
 
+:- pred generate_pred_code_par(module_info::in, pred_id::in,
+    list(c_procedure)::out, global_data::in, global_data::out) is det.
+
+generate_pred_code_par(ModuleInfo, PredId, Predicates, !GlobalData) :-
+    module_info_preds(ModuleInfo, PredInfos),
+    map.lookup(PredInfos, PredId, PredInfo),
+    ProcIds = pred_info_non_imported_procids(PredInfo),
+    generate_pred_code(ModuleInfo, !GlobalData,
+        PredId, PredInfo, ProcIds, Predicates).
+
     % Translate a HLDS predicate to LLDS.
     %
 :- pred generate_pred_code(module_info::in, global_data::in, global_data::out,
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.485
diff -u -r1.485 user_guide.texi
--- doc/user_guide.texi	9 Aug 2006 04:56:36 -0000	1.485
+++ doc/user_guide.texi	15 Aug 2006 06:10:31 -0000
@@ -6740,6 +6740,24 @@
 before going on the next phase on all predicates.
 
 @c @sp 1
+ at c @item --parallel-liveness
+ at c @item --no-parallel-liveness
+ at c @item --parallel-liveness
+ at c Use multiple threads when computing liveness.
+ at c At the moment this option implies @samp{--no-trad-passes},
+ at c and requires the compiler to be built in a
+ at c low-level parallel grade and running with multiple engines.
+
+ at c @sp 1
+ at c @item --parallel-code-gen
+ at c @item --no-parallel-code-gen
+ at c @item --parallel-code-gen
+ at c Use multiple threads when generating code.
+ at c At the moment this option implies @samp{--no-trad-passes},
+ at c and requires the compiler to be built in a
+ at c low-level parallel grade and running with multiple engines.
+
+ at c @sp 1
 @c @item --no-polymorphism
 @c Don't handle polymorphic types.
 @c (Generates slightly more efficient code, but stops
Index: runtime/mercury_context.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_context.c,v
retrieving revision 1.47
diff -u -r1.47 mercury_context.c
--- runtime/mercury_context.c	5 Jul 2006 03:00:43 -0000	1.47
+++ runtime/mercury_context.c	9 Aug 2006 11:59:33 -0000
@@ -237,6 +237,14 @@
 void 
 MR_destroy_context(MR_Context *c)
 {
+#if defined(MR_CONSERVATIVE_GC) && !defined(MR_HIGHLEVEL_CODE)
+    /* Clear stacks to prevent retention of data. */
+    MR_clear_zone_for_GC(c->MR_ctxt_detstack_zone,
+        c->MR_ctxt_detstack_zone->MR_zone_min);
+    MR_clear_zone_for_GC(c->MR_ctxt_nondetstack_zone,
+        c->MR_ctxt_nondetstack_zone->MR_zone_min);
+#endif /* defined(MR_CONSERVATIVE_GC) && !defined(MR_HIGHLEVEL_CODE) */
+
     MR_LOCK(&free_context_list_lock, "destroy_context");
     c->MR_ctxt_next = free_context_list;
     free_context_list = c;
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list