[m-dev.] for review: type specialization [1]

Simon Taylor stayl at cs.mu.OZ.AU
Thu Feb 18 16:14:09 AEDT 1999


Hi Fergus,

This relative diff (full diff for reference_manual.texi) addresses
your concerns, mostly changing the format of type subsitututions.

Thanks,
Simon.

===================================================================
RCS file: RCS/higher_order.m,v
retrieving revision 1.1
diff -u -r1.1 higher_order.m
--- higher_order.m	1999/02/18 03:19:16	1.1
+++ higher_order.m	1999/02/18 03:26:24
@@ -901,6 +901,10 @@
 		Result = no_request
 	).
 
+	% If `--typeinfo-liveness' is set, specializing type `T' to `list(U)'
+	% requires passing in the type-info for `U'. This predicate
+	% works out which extra variables to pass in given the argument
+	% list for the call.
 :- pred compute_extra_typeinfos(higher_order_info::in, list(prog_var)::in,
 		list(prog_var)::out, list(type)::out) is det.
 
===================================================================
RCS file: RCS/make_hlds.m,v
retrieving revision 1.1
diff -u -r1.1 make_hlds.m
--- make_hlds.m	1999/02/18 03:19:02	1.1
+++ make_hlds.m	1999/02/18 04:39:52
@@ -988,6 +988,7 @@
 		    ;
 			report_subst_existq_tvars(PredInfo0, Context,
 					SubExistQVars),
+			io__set_exit_status(1),
 			{ module_info_incr_errors(ModuleInfo0, ModuleInfo) },
 			{ Types = [] },
 			{ ClassContext = constraints([], []) },
@@ -995,7 +996,13 @@
 		    )
 		;
 		    report_non_ground_subst(PredInfo0, Context),
-		    { module_info_incr_errors(ModuleInfo0, ModuleInfo) },
+		    globals__io_lookup_bool_option(halt_at_warn, Halt),
+		    ( { Halt = yes } ->
+		    	{ module_info_incr_errors(ModuleInfo0, ModuleInfo) },
+			io__set_exit_status(1)
+		    ;	
+		    	{ ModuleInfo = ModuleInfo0 }
+		    ),
 		    { ExistQVars = [] },
 		    { Types = [] },
 		    { ClassContext = constraints([], []) },
@@ -1006,6 +1013,7 @@
 		report_unknown_vars_to_subst(PredInfo0, Context,
 		    TVarSet0, UnknownVarsToSub),
 		{ module_info_incr_errors(ModuleInfo0, ModuleInfo) },
+		io__set_exit_status(1),
 		{ ExistQVars = [] },
 		{ Types = [] },
 		{ ClassContext = constraints([], []) },
@@ -1042,10 +1050,11 @@
 
 report_non_ground_subst(PredInfo0, Context) -->
 	report_pragma_type_spec(PredInfo0, Context),
-	io__write_string("  error: the substitution does not make the\n"),
-	io__nl,
+	io__write_string("  warning: the substitution does not make the\n"),
 	prog_out__write_context(Context),
-	io__write_string("  substituted types ground.\n").
+	io__write_string("  substituted types ground.\n"),
+	prog_out__write_context(Context),
+	io__write_string("  The declaration will be ignored.\n").
 
 :- pred report_unknown_vars_to_subst(pred_info, prog_context, tvarset,
 		list(tvar), io__state, io__state).
===================================================================
RCS file: RCS/mercury_to_mercury.m,v
retrieving revision 1.1
diff -u -r1.1 mercury_to_mercury.m
--- mercury_to_mercury.m	1999/02/18 03:26:53	1.1
+++ mercury_to_mercury.m	1999/02/18 04:39:52
@@ -2220,10 +2220,9 @@
 		io__write_int(Arity)
 	),
 
-	io__write_string(", ["),
-	list__foldl(mercury_output_type_subst(VarSet), Subst),
-
-	io__write_string("], "),
+	io__write_string(", ("),
+	io__write_list(Subst, ", ", mercury_output_type_subst(VarSet)),
+	io__write_string("), "),
 	mercury_output_bracketed_sym_name(SpecName, not_next_to_graphic_token),
 	io__write_string(").\n").
 	
@@ -2233,7 +2232,7 @@
 
 mercury_output_type_subst(VarSet, Var - Type) -->
 	mercury_output_var(Var, VarSet, no),
-	io__write_string(" - "),
+	io__write_string(" = "),
 	mercury_output_term(Type, VarSet, no).
 
 %-----------------------------------------------------------------------------%
===================================================================
RCS file: RCS/prog_io_pragma.m,v
retrieving revision 1.1
diff -u -r1.1 prog_io_pragma.m
--- prog_io_pragma.m	1999/02/18 03:26:53	1.1
+++ prog_io_pragma.m	1999/02/18 04:51:42
@@ -390,10 +390,8 @@
 	    (
 		ArityOrModesResult = ok(arity_or_modes(PredName,
 			 Arity, MaybePredOrFunc, MaybeModes)),
-	 	convert_list(TypeSubnTerm, convert_type_spec_pair,
-			TypeSubnResult),
-		(
-			TypeSubnResult = ok(TypeSubn),
+		conjunction_to_list(TypeSubnTerm, TypeSubnList),
+		( list__map(convert_type_spec_pair, TypeSubnList, TypeSubn) ->
 			( MaybeName = yes(SpecializedName0) ->
 				Counter = Counter0,
 				SpecializedName = SpecializedName0
@@ -427,7 +425,6 @@
 				SpecializedName, Arity, MaybePredOrFunc,
 				MaybeModes, TypeSubn, VarSet)))
 		    ;
-			TypeSubnResult = error(_, _),	
 			Counter = Counter0,
 			Result = error(
 	"expected type substitution in `pragma type_spec(...)' declaration",
@@ -1104,7 +1101,7 @@
 :- pred convert_type_spec_pair(term::in, pair(tvar, type)::out) is semidet.
 
 convert_type_spec_pair(Term, TypeSpec) :-
-	Term = term__functor(term__atom("-"), [TypeVarTerm, SpecTypeTerm0], _),
+	Term = term__functor(term__atom("="), [TypeVarTerm, SpecTypeTerm0], _),
 	TypeVarTerm = term__variable(TypeVar0),
 	term__coerce_var(TypeVar0, TypeVar),
 	term__coerce(SpecTypeTerm0, SpecType),
Index: reference_manual.texi
===================================================================
RCS file: /home/staff/zs/imp/mercury/doc/reference_manual.texi,v
retrieving revision 1.120
diff -u -r1.120 reference_manual.texi
--- reference_manual.texi	1999/02/08 22:42:51	1.120
+++ reference_manual.texi	1999/02/18 05:06:14
@@ -3201,6 +3201,8 @@
 * Impurity::                    Users can write impure Mercury code
 * Inlining::                    Pragmas can be used to suggest or prevent
                                 procedure inlining.
+* Type specialization::		Produce specialized versions of polymorphic
+				predicates.
 * Obsolescence::                Library developers can declare old versions
                                 of predicates or functions to be obsolete.
 * Source file name::            The @samp{source_file} pragma and
@@ -4422,6 +4424,83 @@
 simply for performance concerns (inlining can cause unwanted code bloat
 in some cases) or to prevent possibly dangerous inlining when using
 low-level C code.
+
+ at node Type specialization
+ at section Type specialization
+
+The overhead of polymorphism can in some cases be significant, especially
+where polymorphic predicates make heavy use of class method calls or the
+built-in unification and comparison routines. To avoid this, the programmer
+can suggest to the compiler that a specialized version of a procedure should
+be created for a specific set of argument types.
+
+A declaration of the form
+
+ at example
+:- pragma type_spec(@var{Name}/@var{Arity}, @var{Subst}).
+:- pragma type_spec(@var{Name}(@var{Modes}), @var{Subst}).
+ at end example
+
+ at noindent
+suggests to the compiler that a specialized version of the named predicate
+or function should be created with the type substitution given by
+ at var{Subst} applied to the argument types. The second form of the declaration
+only suggests specialization of the specified mode of the predicate.
+
+The substitution is written as a conjunction of bindings of the form
+ at w{@samp{@var{TypeVar} = @var{Type}}}, for example @w{@samp{K = int}} or
+ at w{@samp{(K = int, V = list(int))}}.
+
+The declarations
+
+ at example
+:- pred map__lookup(map(K, V), K, V).
+:- pragma type_spec(map__lookup/3, K = int).
+ at end example
+
+ at noindent
+give a hint to the compiler that a version of @samp{map__lookup/3} should
+be created for integer keys.
+
+An implementation is free to ignore @samp{pragma type_spec} declarations.
+
+ at menu
+* When to use type specialization::
+* Implementation specific details::
+ at end menu
+
+ at node When to use type specialization
+ at subsection When to use type specialization
+
+The set of types for which a predicate or function should be specialized is
+best determined by profiling your application. Overuse of type specialization
+will result in code bloat. 
+
+Type specialization of predicates or functions which
+unify or compare polymorphic variables is most effective when
+the specialized types are built-in types such as @samp{int}, @samp{float}
+and @samp{string}, or enumeration types, since their unification and
+comparison procedures are small and can be inlined.
+
+Predicates or functions which make use of typeclass method calls
+may also be candidates for specialization. Again, this is most effective
+when the called typeclass methods are small enough to be inlined.
+
+ at node Implementation specific details
+ at subsection Implementation specific details
+
+The Melbourne Mercury compiler performs user-requested type specializations
+when invoked with @samp{--user-guided-type-specialization}, which is enabled
+at @samp{-O2}.
+
+The replacement types must be ground. A substitution such as
+ at w{@samp{T = list(U)}} is invalid. The compiler will warn about
+such substitutions, and will ignore the request for specialization.
+This restriction may be lifted in the future.
+ at c The main reason for this restriction is that it is tricky to ensure that
+ at c any extra typeclass_infos that may be needed are ordered the same way in
+ at c different modules. The efficiency gain from replacing a type variable with 
+ at c a non-ground type will usually be pretty small anyway.
 
 @node Obsolescence
 @section Obsolescence



More information about the developers mailing list