[m-rev.] for review: work around slow hipe compilation

Peter Wang wangp at students.csse.unimelb.edu.au
Fri Jun 29 16:46:50 AEST 2007


Estimated hours taken: 5
Branches: main

compiler/erl_code_gen.m:
	The HiPE compiler is extremely slow compiling functions containing long
	case statements involving strings.  Workaround: for a string switch
	with many cases, convert the string to an atom and switch on atoms
	instead.


Index: compiler/erl_code_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/erl_code_gen.m,v
retrieving revision 1.15
diff -u -r1.15 erl_code_gen.m
--- compiler/erl_code_gen.m	20 Jun 2007 05:49:54 -0000	1.15
+++ compiler/erl_code_gen.m	29 Jun 2007 06:36:08 -0000
@@ -586,6 +586,10 @@
 
 duplicate_expr_limit = 10.  % XXX arbitrary
 
+:- func switch_strings_as_atoms_limit = int.
+
+switch_strings_as_atoms_limit = 50. % XXX arbitrary
+
 :- pred erl_gen_switch(prog_var::in, can_fail::in, list(hlds_goal.case)::in,
     code_model::in, instmap::in, prog_context::in, maybe(elds_expr)::in,
     elds_expr::out, erl_gen_info::in, erl_gen_info::out) is det.
@@ -631,12 +635,33 @@
         MaybeSuccessExpr0, MaybeMakeClosure, MaybeSuccessExpr,
         InstMap0, InstMap, !Info),
 
-    % Generate code for each case.
     erl_variable_type(!.Info, Var, VarType),
-    list.map_foldl(
-        erl_gen_case(VarType,
-            CodeModel, InstMap, NonLocalsBoundInCases, MaybeSuccessExpr),
-        CasesList, ErlCases0, !Info),
+    erl_gen_info_get_module_info(!.Info, ModuleInfo),
+    type_util.classify_type(ModuleInfo, VarType) = TypeCategory,
+
+    (if
+        % The HiPE compiler is extremely slow compiling functions containing
+        % long case statements involving strings.  Workaround: for long string
+        % switches, convert the string to an atom and switch on atoms instead.
+        TypeCategory = type_cat_string,
+        list.length(CasesList) > switch_strings_as_atoms_limit
+    then
+        erl_gen_info_new_named_var("Atom", AtomVar, !Info),
+        StringToAtom = elds_eq(expr_from_var(AtomVar),
+            elds_call_builtin("list_to_atom", [expr_from_var(Var)])),
+        MaybeConvertToAtom = yes(StringToAtom),
+        SwitchVar = AtomVar,
+        GenCase = erl_gen_case_on_atom(CodeModel, InstMap,
+            NonLocalsBoundInCases, MaybeSuccessExpr)
+    else
+        MaybeConvertToAtom = no,
+        SwitchVar = Var,
+        GenCase = erl_gen_case(VarType,
+            CodeModel, InstMap, NonLocalsBoundInCases, MaybeSuccessExpr)
+    ),
+
+    % Generate code for each case.
+    list.map_foldl(GenCase, CasesList, ErlCases0, !Info),
     (
         CanFail = can_fail,
         % Add `_ -> fail' default case.
@@ -648,8 +673,9 @@
     ),
 
     % Create the overall switch statement,.
-    CaseExpr = elds_case_expr(expr_from_var(Var), ErlCases),
-    Statement = maybe_join_exprs1(MaybeMakeClosure, CaseExpr).
+    CaseExpr = elds_case_expr(expr_from_var(SwitchVar), ErlCases),
+    Statement = maybe_join_exprs1(MaybeMakeClosure,
+        maybe_join_exprs1(MaybeConvertToAtom, CaseExpr)).
 
 :- pred erl_gen_case(mer_type::in,
     code_model::in, instmap::in, set(prog_var)::in,
@@ -709,6 +735,30 @@
         Size = 0
     ).
 
+:- pred erl_gen_case_on_atom(code_model::in, instmap::in, set(prog_var)::in,
+    maybe(elds_expr)::in, hlds_goal.case::in, elds_case::out, 
+    erl_gen_info::in, erl_gen_info::out) is det.
+
+erl_gen_case_on_atom(CodeModel, InstMap, MustBindNonLocals, MaybeSuccessExpr,
+        case(ConsId, Goal), ELDSCase, !Info) :-
+    ( ConsId = string_const(String0) ->
+        String = String0
+    ;
+        unexpected(this_file, "erl_gen_case_on_atom: non-string const")
+    ),
+    erl_fix_success_expr(InstMap, Goal, MaybeSuccessExpr,
+        MaybeSuccessExprForCase, !Info),
+    erl_gen_goal(CodeModel, InstMap, Goal, MaybeSuccessExprForCase, Statement0,
+        !Info),
+    %
+    % To prevent warnings from the Erlang compiler we must make sure all cases
+    % bind the same set of variables.  This might not be true if the Mercury
+    % compiler knows that a case calls a procedure which throws an exception.
+    %
+    erl_bind_unbound_vars(!.Info, MustBindNonLocals, Goal, InstMap,
+        Statement0, Statement),
+    ELDSCase = elds_case(elds_atom_raw(String), Statement).
+
 %-----------------------------------------------------------------------------%
 % This code is shared by disjunctions and switches.
 
--------------------------------------------------------------------------
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