[m-rev.] for post-commit review: special LLDS code generation for ground terms

Zoltan Somogyi zs at csse.unimelb.edu.au
Mon Jan 5 12:28:03 AEDT 2009


Speed up the LLDS code generator's handling of code that constructs large
ground terms by specializing it.

This diff reduces the compilation time for training_cars_full.m by a further
38% or so, for an overall reduction by about a factor of five since I started.
The time on tools/speedtest stays pretty much the same.

compiler/unify_gen.m:
	Add a mechanism to construct code for from_ground_term_construct
	scopes directly.

compiler/code_gen.m:
	Invoke the new mechanism in unify_gen.m for from_ground_term_construct
	scopes.

	Reorganize some trace goal by duplicating some common support code
	inside them. The compiler wasn't optimizing it away as it should have.

compiler/code_info.m:
	Export a predicate for use by the new code in unify_gen.m.

	Add some debugging predicates.

compiler/opt_debug.m:
	Rename a predicate to better reflect its function.

Zoltan.

Index: unify_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/unify_gen.m,v
retrieving revision 1.189
diff -u -b -r1.189 unify_gen.m
--- unify_gen.m	8 Sep 2008 03:39:06 -0000	1.189
+++ unify_gen.m	2 Jan 2009 16:23:53 -0000
@@ -48,6 +48,9 @@
     test_sense::in, label::out, code_tree::out, code_info::in, code_info::out)
     is det.
 
+:- pred generate_ground_term(prog_var::in, hlds_goal::in,
+    code_info::in, code_info::out) is det.
+
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
@@ -59,6 +62,7 @@
 :- import_module backend_libs.type_class_info.
 :- import_module check_hlds.mode_util.
 :- import_module check_hlds.type_util.
+:- import_module hlds.hlds_code_util.
 :- import_module hlds.hlds_module.
 :- import_module hlds.hlds_out.
 :- import_module hlds.hlds_pred.
@@ -69,6 +73,7 @@
 :- import_module libs.tree.
 :- import_module ll_backend.code_util.
 :- import_module ll_backend.continuation_info.
+:- import_module ll_backend.global_data.
 :- import_module ll_backend.layout.
 :- import_module ll_backend.stack_layout.
 :- import_module mdbcomp.prim_data.
@@ -82,7 +87,9 @@
 :- import_module map.
 :- import_module maybe.
 :- import_module pair.
+:- import_module set.
 :- import_module string.
+:- import_module svmap.
 :- import_module term.
 
 %---------------------------------------------------------------------------%
@@ -1174,9 +1181,9 @@
         LeftMode = top_in,
         RightMode = top_in
     ->
-        % This shouldn't happen, since mode analysis should
-        % avoid creating any tests in the arguments
-        % of a construction or deconstruction unification.
+        % This shouldn't happen, since mode analysis should avoid creating
+        % any tests in the arguments of a construction or deconstruction
+        % unification.
         unexpected(this_file, "test in arg of [de]construction")
     ;
         % Input - Output== assignment ->
@@ -1241,6 +1248,200 @@
 
 %---------------------------------------------------------------------------%
 
+:- type active_ground_term == pair(rval, llds_type).
+:- type active_ground_term_map == map(prog_var, active_ground_term).
+
+generate_ground_term(TermVar, Goal, !CI) :-
+    Goal = hlds_goal(GoalExpr, GoalInfo),
+    NonLocals = goal_info_get_nonlocals(GoalInfo),
+    set.to_sorted_list(NonLocals, NonLocalList),
+    (
+        NonLocalList = []
+        % The term being constructed by the scope is not needed, so there is
+        % nothing to do.
+    ;
+        NonLocalList = [NonLocal],
+        ( NonLocal = TermVar ->
+            ( GoalExpr = conj(plain_conj, Conjuncts) ->
+                get_module_info(!.CI, ModuleInfo),
+                VarTypes = get_var_types(!.CI),
+                get_exprn_opts(!.CI, ExprnOpts),
+                UnboxedFloats = get_unboxed_floats(ExprnOpts),
+                get_static_cell_info(!.CI, StaticCellInfo0),
+                map.init(ActiveMap0),
+                generate_ground_term_conjuncts(ModuleInfo, VarTypes, Conjuncts,
+                    UnboxedFloats, StaticCellInfo0, StaticCellInfo,
+                    ActiveMap0, ActiveMap),
+                map.to_assoc_list(ActiveMap, ActivePairs),
+                ( ActivePairs = [TermVar - GroundTerm] ->
+                    add_forward_live_vars(NonLocals, !CI),
+                    set_static_cell_info(StaticCellInfo, !CI),
+                    GroundTerm = Rval - _,
+                    assign_const_to_var(TermVar, Rval, !CI)
+                ;
+                    unexpected(this_file,
+                        "generate_ground_term: no active pairs")
+                )
+            ;
+                unexpected(this_file, "generate_ground_term: malformed goal")
+            )
+        ;
+            unexpected(this_file, "generate_ground_term: unexpected nonlocal")
+        )
+    ;
+        NonLocalList = [_, _ | _],
+        unexpected(this_file, "generate_ground_term: unexpected nonlocals")
+    ).
+
+:- pred generate_ground_term_conjuncts(module_info::in, vartypes::in,
+    list(hlds_goal)::in, have_unboxed_floats::in,
+    static_cell_info::in, static_cell_info::out,
+    active_ground_term_map::in, active_ground_term_map::out) is det.
+
+generate_ground_term_conjuncts(_ModuleInfo, _VarTypes, [],
+        _UnboxedFloats, !StaticCellInfo, !ActiveMap).
+generate_ground_term_conjuncts(ModuleInfo, VarTypes, [Goal | Goals],
+        UnboxedFloats, !StaticCellInfo, !ActiveMap) :-
+    generate_ground_term_conjunct(ModuleInfo, VarTypes, Goal, UnboxedFloats,
+        !StaticCellInfo, !ActiveMap),
+    generate_ground_term_conjuncts(ModuleInfo, VarTypes, Goals, UnboxedFloats,
+        !StaticCellInfo, !ActiveMap).
+
+:- pred generate_ground_term_conjunct(module_info::in, vartypes::in,
+    hlds_goal::in, have_unboxed_floats::in,
+    static_cell_info::in, static_cell_info::out,
+    active_ground_term_map::in, active_ground_term_map::out) is det.
+
+generate_ground_term_conjunct(ModuleInfo, VarTypes, Goal, UnboxedFloats,
+        !StaticCellInfo, !ActiveMap) :-
+    Goal = hlds_goal(GoalExpr, _GoalInfo),
+    (
+        GoalExpr = unify(_, _, _, Unify, _),
+        Unify = construct(Var, ConsId, Args, _, _, _, SubInfo),
+        SubInfo = no_construct_sub_info
+    ->
+        map.lookup(VarTypes, Var, Type),
+        ConsTag = cons_id_to_tag(ModuleInfo, Type, ConsId),
+        generate_ground_term_conjunct_tag(Var, ConsTag, Args, UnboxedFloats,
+            !StaticCellInfo, !ActiveMap)
+    ;
+        unexpected(this_file,
+            "generate_ground_term_conjunct: malformed goal")
+    ).
+
+:- pred generate_ground_term_conjunct_tag(prog_var::in, cons_tag::in,
+    list(prog_var)::in, have_unboxed_floats::in,
+    static_cell_info::in, static_cell_info::out,
+    active_ground_term_map::in, active_ground_term_map::out) is det.
+
+generate_ground_term_conjunct_tag(Var, ConsTag, Args, UnboxedFloats,
+        !StaticCellInfo, !ActiveMap) :-
+    (
+        (
+            ConsTag = string_tag(String),
+            Const = llconst_string(String),
+            Type = string
+        ;
+            ConsTag = int_tag(Int),
+            Const = llconst_int(Int),
+            Type = integer
+        ;
+            ConsTag = foreign_tag(Lang, Val),
+            expect(unify(Lang, lang_c), this_file,
+                "foreign_tag for language other than C"),
+            Const = llconst_foreign(Val, integer),
+            Type = integer
+        ;
+            ConsTag = float_tag(Float),
+            Const = llconst_float(Float),
+            (
+                UnboxedFloats = have_unboxed_floats,
+                Type = float
+            ;
+                UnboxedFloats = do_not_have_unboxed_floats,
+                Type = data_ptr
+            )
+        ),
+        ActiveGroundTerm = const(Const) - Type,
+        svmap.det_insert(Var, ActiveGroundTerm, !ActiveMap)
+    ;
+        ConsTag = shared_local_tag(Ptag, Stag),
+        Rval = mkword(Ptag, unop(mkbody, const(llconst_int(Stag)))),
+        ActiveGroundTerm = Rval - data_ptr,
+        svmap.det_insert(Var, ActiveGroundTerm, !ActiveMap)
+    ;
+        ConsTag = reserved_address_tag(RA),
+        Rval = generate_reserved_address(RA),
+        rval_type(Rval, RvalType),
+        ActiveGroundTerm = Rval - RvalType,
+        svmap.det_insert(Var, ActiveGroundTerm, !ActiveMap)
+    ;
+        ConsTag = shared_with_reserved_addresses_tag(_, ActualConsTag),
+        generate_ground_term_conjunct_tag(Var, ActualConsTag, Args,
+            UnboxedFloats, !StaticCellInfo, !ActiveMap)
+    ;
+        ConsTag = no_tag,
+        (
+            Args = [],
+            unexpected(this_file,
+                "generate_ground_term_conjunct_tag: no_tag arity != 1")
+        ;
+            Args = [Arg],
+            svmap.det_remove(Arg, RvalType, !ActiveMap),
+            svmap.det_insert(Var, RvalType, !ActiveMap)
+        ;
+            Args = [_, _ | _],
+            unexpected(this_file,
+                "generate_ground_term_conjunct_tag: no_tag arity != 1")
+        )
+    ;
+        (
+            ConsTag = single_functor_tag,
+            Ptag = 0
+        ;
+            ConsTag = unshared_tag(Ptag)
+        ),
+        generate_ground_term_args(Args, ArgRvalsTypes, !ActiveMap),
+        add_scalar_static_cell(ArgRvalsTypes, DataAddr, !StaticCellInfo),
+        MaybeOffset = no,
+        CellPtrConst = const(llconst_data_addr(DataAddr, MaybeOffset)),
+        Rval = mkword(Ptag, CellPtrConst),
+        ActiveGroundTerm = Rval - data_ptr,
+        svmap.det_insert(Var, ActiveGroundTerm, !ActiveMap)
+    ;
+        ConsTag = shared_remote_tag(Ptag, Stag),
+        generate_ground_term_args(Args, ArgRvalsTypes, !ActiveMap),
+        StagRvalType = const(llconst_int(Stag)) - integer,
+        AllRvalsTypes = [StagRvalType | ArgRvalsTypes],
+        add_scalar_static_cell(AllRvalsTypes, DataAddr, !StaticCellInfo),
+        MaybeOffset = no,
+        CellPtrConst = const(llconst_data_addr(DataAddr, MaybeOffset)),
+        Rval = mkword(Ptag, CellPtrConst),
+        ActiveGroundTerm = Rval - data_ptr,
+        svmap.det_insert(Var, ActiveGroundTerm, !ActiveMap)
+    ;
+        ( ConsTag = pred_closure_tag(_, _, _)
+        ; ConsTag = type_ctor_info_tag(_, _, _)
+        ; ConsTag = base_typeclass_info_tag(_, _, _)
+        ; ConsTag = tabling_info_tag(_, _)
+        ; ConsTag = table_io_decl_tag(_, _)
+        ; ConsTag = deep_profiling_proc_layout_tag(_, _)
+        ),
+        unexpected(this_file,
+            "generate_ground_term_conjunct_tag: unexpected tag")
+    ).
+
+:- pred generate_ground_term_args(list(prog_var)::in,
+    assoc_list(rval, llds_type)::out,
+    active_ground_term_map::in, active_ground_term_map::out) is det.
+
+generate_ground_term_args([], [], !ActiveMap).
+generate_ground_term_args([Var | Vars], [RvalType | RvalsTypes], !ActiveMap) :-
+    svmap.det_remove(Var, RvalType, !ActiveMap),
+    generate_ground_term_args(Vars, RvalsTypes, !ActiveMap).
+
+%---------------------------------------------------------------------------%
+
 :- pred var_type_msg(mer_type::in, string::out) is det.
 
 var_type_msg(Type, Msg) :-
Index: code_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/code_gen.m,v
retrieving revision 1.178
diff -u -b -r1.178 code_gen.m
--- code_gen.m	23 Dec 2008 01:37:29 -0000	1.178
+++ code_gen.m	2 Jan 2009 15:11:01 -0000
@@ -75,23 +75,22 @@
     % the generic data structures before and after the actual code generation,
     % which is delegated to goal-specific predicates.
 
-    get_forward_live_vars(!.CI, ForwardLiveVarsBeforeGoal),
-
-    % This block of code should be optimized away if the trace goals
-    % are not enabled.
+    trace [compiletime(flag("codegen_goal")), io(!IO)] (
+        some [ModuleInfo, VarSet, GoalDesc] (
     code_info.get_module_info(!.CI, ModuleInfo),
     code_info.get_varset(!.CI, VarSet),
     GoalDesc = describe_goal(ModuleInfo, VarSet, Goal),
 
-    trace [compiletime(flag("codegen_goal")), io(!IO)] (
         ( should_trace_code_gen(!.CI) ->
             io.format("\nGOAL START: %s\n", [s(GoalDesc)], !IO)
         ;
             true
         )
+        )
     ),
 
     % Make any changes to liveness before Goal.
+    get_forward_live_vars(!.CI, ForwardLiveVarsBeforeGoal),
     Goal = hlds_goal(GoalExpr, GoalInfo),
     HasSubGoals = goal_expr_has_subgoals(GoalExpr),
     pre_goal_update(GoalInfo, HasSubGoals, !CI),
@@ -181,6 +180,11 @@
         Code = empty
     ),
     trace [compiletime(flag("codegen_goal")), io(!IO)] (
+        some [ModuleInfo, VarSet, GoalDesc] (
+            code_info.get_module_info(!.CI, ModuleInfo),
+            code_info.get_varset(!.CI, VarSet),
+            GoalDesc = describe_goal(ModuleInfo, VarSet, Goal),
+
         ( should_trace_code_gen(!.CI) ->
             io.format("\nGOAL FINISH: %s\n", [s(GoalDesc)], !IO),
             InstrLists = tree.flatten(Code),
@@ -189,6 +193,7 @@
         ;
             true
         )
+        )
     ).
 
 :- func compute_deep_save_excp_vars(proc_info) = list(prog_var).
@@ -257,9 +262,14 @@
         switch_gen.generate_switch(CodeModel, Var, CanFail, CaseList, GoalInfo,
             Code, !CI)
     ;
-        GoalExpr = scope(Reason, Goal),
+        GoalExpr = scope(Reason, SubGoal),
+        ( Reason = from_ground_term(TermVar, from_ground_term_construct) ->
+            unify_gen.generate_ground_term(TermVar, SubGoal, !CI),
+            Code = empty
+        ;
         commit_gen.generate_scope(Reason, CodeModel, GoalInfo,
-            ForwardLiveVarsBeforeGoal, Goal, Code, !CI)
+                ForwardLiveVarsBeforeGoal, SubGoal, Code, !CI)
+        )
     ;
         GoalExpr = generic_call(GenericCall, Args, Modes, Det),
         call_gen.generate_generic_call(CodeModel, GenericCall, Args,
Index: code_info.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/code_info.m,v
retrieving revision 1.370
diff -u -b -r1.370 code_info.m
--- code_info.m	2 Jan 2009 03:12:06 -0000	1.370
+++ code_info.m	2 Jan 2009 12:59:33 -0000
@@ -51,6 +51,7 @@
 :- import_module assoc_list.
 :- import_module bool.
 :- import_module counter.
+:- import_module io.
 :- import_module list.
 :- import_module map.
 :- import_module maybe.
@@ -76,9 +77,9 @@
 :- import_module ll_backend.opt_debug.
 :- import_module ll_backend.var_locn.
 :- import_module parse_tree.prog_type.
+:- import_module parse_tree.mercury_to_mercury.
 
 :- import_module int.
-:- import_module io.
 :- import_module pair.
 :- import_module set.
 :- import_module stack.
@@ -3245,6 +3246,9 @@
 
 :- interface.
 
+:- pred add_forward_live_vars(set(prog_var)::in,
+    code_info::in, code_info::out) is det.
+
 :- pred get_known_variables(code_info::in, list(prog_var)::out) is det.
 
 :- pred variable_is_forward_live(code_info::in, prog_var::in) is semidet.
@@ -3259,9 +3263,6 @@
 
 :- implementation.
 
-:- pred add_forward_live_vars(set(prog_var)::in,
-    code_info::in, code_info::out) is det.
-
 :- pred rem_forward_live_vars(set(prog_var)::in,
     code_info::in, code_info::out) is det.
 
@@ -4607,6 +4608,20 @@
     %
 :- pred should_trace_code_gen(code_info::in) is semidet.
 
+:- type code_info_component
+    --->    cic_forward_live_vars
+    ;       cic_zombies
+    ;       cic_temps_in_use
+    ;       cic_par_conj_depth.
+
+    % Print the selected parts of the code_info.
+    %
+    % If you need to print a part that is not currently selectable, make it
+    % selectable.
+    %
+:- pred output_code_info(list(code_info_component)::in, code_info::in,
+    io::di, io::uo) is det.
+
 :- implementation.
 
 should_trace_code_gen(CI) :-
@@ -4617,6 +4632,39 @@
     globals.lookup_int_option(Globals, debug_code_gen_pred_id, DebugPredIdInt),
     PredIdInt = DebugPredIdInt.
 
+output_code_info(Components, CI, !IO) :-
+    CI = code_info(Static, LocDep, _Persistent),
+    VarSet = Static ^ cis_varset,
+    LocDep = code_info_loc_dep(ForwardLiveVars, _InstMap, Zombies,
+        _VarLocnInfo, TempsInUse, _FailInfo, ParConjDepth),
+    ( list.member(cic_forward_live_vars, Components) ->
+        io.write_string("forward live vars: ", !IO),
+        mercury_output_vars(VarSet, yes, set.to_sorted_list(ForwardLiveVars),
+            !IO),
+        io.nl(!IO)
+    ;
+        true
+    ),
+    ( list.member(cic_zombies, Components) ->
+        io.write_string("zombies: ", !IO),
+        mercury_output_vars(VarSet, yes, set.to_sorted_list(Zombies), !IO),
+        io.nl(!IO)
+    ;
+        true
+    ),
+    ( list.member(cic_temps_in_use, Components) ->
+        io.write_string("temps_in_use: ", !IO),
+        io.write_string(dump_lvals(no, set.to_sorted_list(TempsInUse)), !IO),
+        io.nl(!IO)
+    ;
+        true
+    ),
+    ( list.member(cic_par_conj_depth, Components) ->
+        io.format("par_conj_depth: %d\n", [i(ParConjDepth)], !IO)
+    ;
+        true
+    ).
+
 :- pred output_resume_map(prog_varset::in, map(prog_var, set(lval))::in,
     io::di, io::uo) is det.
 
Index: opt_debug.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/opt_debug.m,v
retrieving revision 1.208
diff -u -b -r1.208 opt_debug.m
--- opt_debug.m	28 Nov 2008 06:36:59 -0000	1.208
+++ opt_debug.m	2 Jan 2009 12:48:16 -0000
@@ -69,12 +69,12 @@
 
 :- func dump_livevals(maybe(proc_label), lvalset) = string.
 
-:- func dump_livelist(maybe(proc_label), list(lval)) = string.
-
 :- func dump_reg(reg_type, int) = string.
 
 :- func dump_lval(maybe(proc_label), lval) = string.
 
+:- func dump_lvals(maybe(proc_label), list(lval)) = string.
+
 :- func dump_rval(maybe(proc_label), rval) = string.
 
 :- func dump_rvals(maybe(proc_label), list(rval)) = string.
@@ -259,17 +259,7 @@
         dump_livemaplist(MaybeProcLabel, Livemaplist).
 
 dump_livevals(MaybeProcLabel, Lvalset) =
-    dump_livelist(MaybeProcLabel, set.to_sorted_list(Lvalset)).
-
-dump_livelist(MaybeProcLabel, Lvals) =
-    dump_livelist_2(MaybeProcLabel, Lvals, "").
-
-:- func dump_livelist_2(maybe(proc_label), list(lval), string) = string.
-
-dump_livelist_2(_, [], _) = "".
-dump_livelist_2(MaybeProcLabel, [Lval | Lvallist], Prefix) =
-    Prefix ++ dump_lval(MaybeProcLabel, Lval) ++
-        dump_livelist_2(MaybeProcLabel, Lvallist, " ").
+    dump_lvals(MaybeProcLabel, set.to_sorted_list(Lvalset)).
 
 dump_reg(reg_r, N) =
     "r" ++ int_to_string(N).
@@ -318,6 +308,16 @@
 dump_lval(_, global_var_ref(env_var_ref(VarName))) =
     "global_var_ref(env_var_ref(" ++ VarName ++ "))".
 
+dump_lvals(MaybeProcLabel, Lvals) =
+    dump_lvals_2(MaybeProcLabel, Lvals, "").
+
+:- func dump_lvals_2(maybe(proc_label), list(lval), string) = string.
+
+dump_lvals_2(_, [], _) = "".
+dump_lvals_2(MaybeProcLabel, [Lval | Lvallist], Prefix) =
+    Prefix ++ dump_lval(MaybeProcLabel, Lval) ++
+        dump_lvals_2(MaybeProcLabel, Lvallist, " ").
+
 dump_rval(MaybeProcLabel, lval(Lval)) =
     dump_lval(MaybeProcLabel, Lval).
 dump_rval(_, var(Var)) =
--------------------------------------------------------------------------
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