[m-rev.] for review: [CTGC] generate optimised versions, reuse pragmas

Julien Fischer juliensf at cs.mu.OZ.AU
Wed Jun 7 18:50:37 AEST 2006


On Tue, 6 Jun 2006, Nancy Mazur wrote:

> Hi,
>
> for anybody to review....
>
> I've got one problem with the change below which also contains the mechanism
> to output structure_reuse pragma's, as well as reading them back in. Each
> structure reuse pragma is related to a procedure. It dictates the
> conditions which a caller of this procedure needs to meet in order to
> safely replace the original call by a call to the optimised version of that
> procedure. This means that for each procedure, we create a separate (optimised)
> version (if optimisations are possible of course) with a compiler-generated
> name. This name is generated using the function:
>
> 	generate_reuse_name(module_info, pred_proc_id) = reuse_name.
>
> defined in structure_reuse.split,
> which uses the predicate
>
> 	prog_util.make_pred_name_with_context/7
>
> The problem is that this generates a name with a whole bunch of "__", and of
> course, once you print this name out, and read it back in, you get a sym_name
> with the strangest set of qualifiers.

Why (and where) do you need to print it out and read it back in?  In the .opt
or .trans_opt files?  I would have thought that the presence of a reuse pragma
in those files would be sufficient to indicate the presence of optimized
versions of the procedures.

> Just as an example. If I generate and print the name:
> 	'concat.ctgc__pred__concatenate__0__0'
> then reading it back in (using prog_io.sym_name_and_args/3), and printing
> it back out again (in a hlds_dump file), this looks like this:
> 	((('concat.ctgc'.(pred)).concatenate).'0').'0'
>
> I don't really know what already exists to print and parse such sym_names
> correctly.  Can someone help me out on this one?

I don't see why the reuse pragmas need to include the name of the optimised
version at all.  It ought to be enough to know what the name of the original
procedure, what the reuse description was and that an optimised version
exists.  The importing module ought to be able to reconstruct the name of the
optimised version given this information.

(I think we do a similar thing with the specialized versions created by
unused argument analysis (compiler/unused_args.m) - so you might want
to have a look there.)

> Estimated hours taken: 15
> Branches: main
>
> Create optimised versions for all the procedures in which possibilities for
> structure reuse are detected.

s/in which/for which/

That's potentially going to be a rather large number of them.

> Put the mechanism in place to generate reuse
> pragma's, and to parse them back in.

s/pragma's/pragmas/



>
> compiler/add_pragma.m:
> compiler/make_hlds_passes.m:
> compiler/mercury_to_mercury.m:
> compiler/prog_ctgc.m:
> compiler/prog_io_pragma.m:
> compiler/structure_reuse.analysis.m:
> compiler/trans_opt.m:
> 	Add the mechanism to output and parse the structure_reuse pragma's.
>

s/pragma's/pragmas/

> compiler/hlds_module.m:
> 	Simplify the type structure_reuse_info.
>
> compiler/hlds_pred.m:
> 	Add structure sharing information at the level of each individual
> 	procedure. This information consists of a description of any reuse
> 	conditions that have been derived for that procedure.
>
> compiler/prog_item.m:
> compiler/prog_data.m:
> 	Add types for the public representation of reuse conditions.
> 	(remove the previous name "reuse_tuple", which simply does not sound
> 	adequate).
>
> compiler/prog_type.m:
> 	Add functions to remove all typeinfo-vars from a
> 	given list (resp. set) of vars.
>
> compiler/structure_reuse.domain.m:
> 	Conversion procedures between the public and private representation
> 	for structure reuse conditions.
>
> compiler/structure_reuse.indirect.m:
> 	Do not try to replace call information even when you know the
> 	pred_proc_id of the reuse version of that call (which is the case for
> 	imported procedures with reuse). It is more consistent
> 	to do this at the same time when all the other conversions are done,
> 	i.e. when generating the optimised versions of the procedures with
> 	reuse (even with unconditional reuse).
>
> compiler/structure_reuse.lbu.m:
> compiler/structure_reuse.lfu.m:
> 	Make sure that no lbu/lfu information regarding typeinfo-vars is
> 	recorded. These variables are irrelevant for the analysis. On the
> 	contrary, keeping these variables may cause errors:
> 	the generated (reuse) pragma's may end up containing these
> 	typeinfo-vars, when reading these pragma's back in, it becomes
> 	troublesome to match them with the corresponding predicate signatures,
> 	as these signatures do not contain such typeinfo-headvars.
>
> compiler/structure_reuse.analysis.m:
> compiler/structure_reuse.m:
> compiler/structure_reuse.split.m:
> 	Create optimised versions for the procedures for which
> 	reuse was detected.
> 	(structure_reuse.split.m = new file)
>

Why is it called split?  (That doesn't immediately mean anything to me.)

> compiler/structure_sharing.analysis.m:
> 	Add some documentation.
>
>
>
>
> Index: compiler/add_pragma.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/add_pragma.m,v
> retrieving revision 1.33
> diff -u -d -r1.33 add_pragma.m
> --- compiler/add_pragma.m	5 Jun 2006 02:26:06 -0000	1.33
> +++ compiler/add_pragma.m	6 Jun 2006 13:31:22 -0000
> @@ -56,6 +56,11 @@
>      maybe(structure_sharing_domain)::in, prog_context::in,
>      module_info::in, module_info::out, io::di, io::uo) is det.
>
> +:- pred add_pragma_structure_reuse(pred_or_func::in, sym_name::in,
> +    list(mer_mode)::in, list(prog_var)::in, list(mer_type)::in,
> +    maybe(structure_reuse_domain)::in, maybe(sym_name)::in, prog_context::in,
> +    module_info::in, module_info::out, io::di, io::uo) is det.
> +
>      % module_add_pragma_import:
>      %
>      % Handles `pragma import' declarations, by figuring out which predicate
> @@ -1227,6 +1232,99 @@
>          %   module_info_incr_errors(!ModuleInfo)
>      ).
>
> +add_pragma_structure_reuse(_PredOrFunc, _SymName, _ModeList, _HeadVars,
> +        _Types, no, _MaybeReusePredName, _Context, !ModuleInfo, !IO).
> +add_pragma_structure_reuse(PredOrFunc, SymName, ModeList, HeadVars,
> +        Types, yes(ReuseDomain), MaybeReusePredName,
> +        Context, !ModuleInfo, !IO):-
> +    module_info_get_predicate_table(!.ModuleInfo, Preds),
> +    list.length(ModeList, Arity),
> +    (
> +        predicate_table_search_pf_sym_arity(Preds, is_fully_qualified,
> +            PredOrFunc, SymName, Arity, PredIds),
> +        PredIds = [_ | _]
> +    ->
> +        ( PredIds = [PredId] ->
> +            module_info_preds(!.ModuleInfo, PredTable0),
> +            map.lookup(PredTable0, PredId, PredInfo0),
> +            pred_info_get_procedures(PredInfo0, ProcTable0),
> +            map.to_assoc_list(ProcTable0, ProcList),
> +            (
> +                get_procedure_matching_declmodes(ProcList, ModeList,
> +                    !.ModuleInfo, ProcId)
> +            ->
> +                map.lookup(ProcTable0, ProcId, ProcInfo0),
> +
> +                % Rename headvars/types to those used in the proc_info.
> +                proc_info_get_headvars(ProcInfo0, ProcHeadVars),
> +
> +                % As the HeadVars recorded in the pragma may contain additional
> +                % vars (e.g. typeinfos), and in the same time ProcHeadVars does
> +                % not, make sure to remove all TypeInfo-vars from HeadVars,
> +                % the same for the list Types.
> +                Diff = list.length(HeadVars) - list.length(ProcHeadVars),
> +                (
> +                    list.drop(Diff, HeadVars, RemHeadVars0),
> +                    list.drop(Diff, Types, RemTypes0)
> +                ->
> +                    RemHeadVars = RemHeadVars0,
> +                    RemTypes = RemTypes0
> +                ;
> +                    unexpected(this_file, "Impossible situation.")
> +                ),

In my experience this sort of things tends to be highly breakable.  The
approach I took with the with termination2_info pragmas was to delay
further processing of the pragam until after the polymorphism pass has
been run (in fact until the beginning of the termination 2 pass - see
term_constr_initial.preprocess_module/4).

I think that kind of approach would also be better here, i.e. delay
further processing of the structure_reuse pragmas until the information
in them is actually needed.

> +                map.from_corresponding_lists(RemHeadVars, ProcHeadVars,
> +                    MapHeadVars),
> +                pred_info_get_arg_types(PredInfo0, ArgTypes),
> +                TypeSubst0 = map.init,
> +                (
> +                    type_unify_list(RemTypes, ArgTypes, [], TypeSubst0,
> +                        TypeSubst1)
> +                ->
> +                    TypeSubst = TypeSubst1
> +                ;
> +                    TypeSubst = TypeSubst0
> +                ),
> +                rename_structure_reuse_domain(MapHeadVars, TypeSubst,
> +                    ReuseDomain, RenamedReuseDomain),
> +                proc_info_set_structure_reuse(RenamedReuseDomain,
> +                    ProcInfo0, ProcInfo1),
> +                (
> +                    MaybeReusePredName = no,
> +                    ProcInfo = ProcInfo1
> +                ;
> +                    MaybeReusePredName = yes(ReusePredName),
> +                    proc_info_set_structure_reuse_pred_name(ReusePredName,
> +                        ProcInfo1, ProcInfo)
> +                ),
> +                map.det_update(ProcTable0, ProcId, ProcInfo, ProcTable),
> +                pred_info_set_procedures(ProcTable, PredInfo0, PredInfo),
> +                map.det_update(PredTable0, PredId, PredInfo, PredTable),
> +                module_info_set_preds(PredTable, !ModuleInfo)
> +
> +            ;
> +                module_info_incr_errors(!ModuleInfo),
> +                Pieces = [words("Error: `:- pragma structure_reuse'"),
> +                    words("declaration for undeclared mode of"),
> +                    simple_call_id(simple_call_id(PredOrFunc, SymName, Arity)),
> +                    suffix(".")],
> +                write_error_pieces(Context, 0, Pieces, !IO)
> +            )
> +        ;
> +            module_info_incr_errors(!ModuleInfo),
> +            Pieces = [words("Error: ambiguous predicate name"),
> +                simple_call_id(simple_call_id(PredOrFunc, SymName, Arity)),
> +                words("in"), fixed("`pragma structure_reuse'.")],
> +            write_error_pieces(Context, 0, Pieces, !IO)
> +        )
> +    ;
> +        % XXX This happens in `.trans_opt' files sometimes --
> +        % so just ignore it
> +        true
> +        %   undefined_pred_or_func_error(SymName, Arity, Context,
> +        %       "`:- pragma structure_sharing' declaration",
> +        %       !IO),
> +        %   module_info_incr_errors(!ModuleInfo)
> +    ).
>  %-----------------------------------------------------------------------------%
>
>  add_pragma_termination_info(PredOrFunc, SymName, ModeList,

...

> Index: compiler/structure_reuse.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/structure_reuse.m,v
> retrieving revision 1.3
> diff -u -d -r1.3 structure_reuse.m
> --- compiler/structure_reuse.m	29 May 2006 13:04:35 -0000	1.3
> +++ compiler/structure_reuse.m	6 Jun 2006 13:31:48 -0000
> @@ -21,6 +21,7 @@
>  	:- include_module lbu.
>  	:- include_module direct.
>  	:- include_module indirect.
> +	:- include_module split.
>
>  % :- include_module util.
>  :- include_module domain.



> Index: compiler/structure_reuse.split.m
> ===================================================================
> RCS file: compiler/structure_reuse.split.m
> diff -N compiler/structure_reuse.split.m
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ compiler/structure_reuse.split.m	6 Jun 2006 13:31:48 -0000
> @@ -0,0 +1,302 @@
> +%------------------------------------------------------------------------------%
> +% vim: ft=mercury ff=unix ts=4 sw=4 et
> +%------------------------------------------------------------------------------%
> +% Copyright (C) 2006 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.
> +%-----------------------------------------------------------------------------%
> +%
> +% File: structure_reuse.split.m
> +% Main authors: nancy
> +%
> +% Provide the functionality to create optimised versions of those procedures
> +% for which reuse was detected.
> +%

I don't like split as a name for this module.  How about:

	structure_reuse.reuse_versions or even structure_reuse.versions
...

> Index: compiler/trans_opt.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/trans_opt.m,v
> retrieving revision 1.39
> diff -u -d -r1.39 trans_opt.m
> --- compiler/trans_opt.m	5 Jun 2006 02:26:11 -0000	1.39
> +++ compiler/trans_opt.m	6 Jun 2006 13:31:49 -0000
> @@ -93,6 +93,8 @@
>  :- import_module parse_tree.prog_io.
>  :- import_module parse_tree.prog_out.
>  :- import_module transform_hlds.ctgc.
> +:- import_module transform_hlds.ctgc.structure_reuse.
> +:- import_module transform_hlds.ctgc.structure_reuse.analysis.
>  :- import_module transform_hlds.ctgc.structure_sharing.
>  :- import_module transform_hlds.ctgc.structure_sharing.analysis.
>  :- import_module transform_hlds.exception_analysis.
> @@ -104,6 +106,7 @@
>
>  :- import_module list.
>  :- import_module map.
> +:- import_module pair.
>  :- import_module set.
>  :- import_module string.
>  :- import_module term.
> @@ -147,8 +150,21 @@
>          list.foldl(term_constr_main.output_pred_termination2_info(Module),
>              PredIds, !IO),
>
> +        % XXX I have a strong feeling that also writing termination info and
> +        % exception information should be limited to those pred_ids that do not
> +        % correspond to compiler generated reuse versions of other predicates.
> +        %

Yes, you should exclude the reuse versions.  (Since reuse should not affect
the termination/exception properties of a procedure, if we want to know
what they are we should just look up the information for the original
version.)

Julien.
--------------------------------------------------------------------------
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