[m-rev.] for review: new termination analyser (part 5 of 6)

Julien Fischer juliensf at cs.mu.OZ.AU
Sat Apr 2 16:14:40 AEST 2005


On Sat, 2 Apr 2005, Mark Brown wrote:

> On 24-Mar-2005, Julien Fischer <juliensf at cs.mu.OZ.AU> wrote:
> >
> > +%-----------------------------------------------------------------------------%
> > Index: compiler/term_constr_errors.m
> > ===================================================================
> > RCS file: compiler/term_constr_errors.m
> > diff -N compiler/term_constr_errors.m
> > --- /dev/null	1 Jan 1970 00:00:00 -0000
> > +++ compiler/term_constr_errors.m	9 Mar 2005 03:43:17 -0000
> > +%-----------------------------------------------------------------------------%
> > +%
> > +% Termination 2 Errors
> > +%
> > +
> > +% The termination errors are all in reference to possible non-termination.
> > +% While it is possible for pass 1 to go amiss the worst that will happen
> > +% (barring an abnormal abort) is that the size of the arguments will be
> > +% unconstrained.
> > +
> > +:- type termination2_error
> > +	--->		imported_pred
> > +				% Termination could not be proved because
> > +				% it depends upon information from another
> > +				% module and that information is not
> > +				% available.
> > +
> > +	;		can_loop_proc_called(pred_proc_id, pred_proc_id)
> > +				% Termination could not be proved because
> > +				% the procedure called another procedure
> > +				% that may not terminate.
> > +
> > +	;		cond_not_satisfied
> > +				% Termination could not be proved because
> > +				% no set of decreasing argument could e found.
>
> s/could e/could be/
>
Fixed.


> > Index: compiler/term_constr_fixpoint.m
> > ===================================================================
> > RCS file: compiler/term_constr_fixpoint.m
> > diff -N compiler/term_constr_fixpoint.m
> > --- /dev/null	1 Jan 1970 00:00:00 -0000
> > +++ compiler/term_constr_fixpoint.m	24 Mar 2005 04:20:56 -0000
> > +%-----------------------------------------------------------------------------%
> > +
> > +    % Calculate the next approximation to the argument size constraints.
> > +    %
> > +    % ChangeFlag is `yes' if the constraints for any procedure in the SCC
> > +    % have changed since the previous iteration.
> > +    %
> > +:- pred do_fixpoint_calculation(fixpoint_options::in, list(pred_proc_id)::in,
> > +    int::in, term2_errors::out, module_info::in, module_info::out,
> > +    io::di, io::uo) is det.
>
> The comment isn't right, since this predicate does the full calculation
> rather than just one iteration, and also there is no ChangeFlag.
>
That comment was out of date.  I've changed it to:

	% Derive the argument size constraints for the procedures in
	% this SCC.


> > +:- func fixpoint_options_init(widening, int) = fixpoint_options.
>
> The arguments to this function should be documented.
>
Done.


> > +%------------------------------------------------------------------------------%
> > +%
> > +% Perform a fixpoint iteration on the AR.
>
> This does the full calculation, right?  The next section of code does
> an iteration.
>
Yes it does the full calculation.  I've fixed the section heading here.

> > +        %
> > +        % Look up the constraints obtained during the previous
> > +        % iteration.
> > +        %
> > +        ArgSizeInfo = lookup_proc_constr_arg_size_info(ModuleInfo, PPId),
> > +        %
> > +        % NOTE: `!.Polyhedron' is the set of constraints obtained by
> > +        % *this* iteration.  `OldPolyhedron' is the set of constraints
> > +        % obtained by the *previous* iteration -- which may in fact
> > +        % be `empty' (false).
> > +        %
> > +        (
> > +            % If there were no constraints for the procedure then
> > +            % we are at the beginning of the analysis.
> > +            %
> > +            ArgSizeInfo = no,
> > +            OldPolyhedron = polyhedron.empty
> > +        ;
> > +            ArgSizeInfo = yes(SizeInfo),
> > +            SizeInfo = OldPolyhedron
>
> That would be easier to understand if OldPolyhedron was on the left.
>
Done.

> > +                %
> > +                % Set any zero_vars in the constraints
> > +                % to zero (ie. delete the terms).  We need
> > +                % to do this when a polymorphic arguments
>
> s/when a/when/
>
Fixed.


> > +%------------------------------------------------------------------------------%
> > +%
> > +% Predicates for handling disjunctions.
> > +%
> > +
> > +    % This version computes the convex hull linearly.
> > +    % That is, ( A ; B ; C ; D) is processed as:
> > +    %
> > +    %  ((((identity \/ A ) \/ B ) \/ C ) \/ D)
> > +    %
> > +:- pred traverse_abstract_disj_linearly(abstract_goals::in,
> > +    size_vars::in, fixpoint_info::in, polyhedron::in, polyhedron::out)
> > +    is det.
> > +
> > +traverse_abstract_disj_linearly(Goals, Locals, Info, !Polyhedron) :-
> > +    list.foldl(traverse_abstract_disjunct_linearly(Info, Locals),
> > +        Goals, polyhedron.empty, ConvexUnion),
> > +    polyhedron.intersection(ConvexUnion, !Polyhedron).
> > +
> > +:- pred traverse_abstract_disjunct_linearly(fixpoint_info::in,
> > +    size_vars::in, abstract_goal::in, polyhedron::in, polyhedron::out)
> > +    is det.
>
> Why not call this "traverse_abstract_disj_linearly_2"?
>
Done.

> > +    % This assumes that the operation in question is associative and
> > +    % commutative.
> > +    %
> > + :- func pairwise_map(func(T, T) = T, list(T)) = T.
>
> No biggie, but this bears more resemblance to a "fold" than to a "map".
>
I suppose it does - at the time I couldn't think what to call it
so I just left it as pairwise_map.  Some other ideas are
pairwise_condense or pairwise_merge_with_op.  Any suggestions?


> > +:- func test_fixpoint(polyhedron, polyhedron, size_varset) = bool.
> > +
> > +test_fixpoint(NewPoly, OldPoly, Varset) = ChangeFlag :-
> > +    %
> > +    % Constraints from this iteration.
> > +    %
> > +    NewConstraints = polyhedron.non_false_constraints(NewPoly),
> > +    %
> > +    % Constraints from previous iteration.
> > +    %
> > +    OldConstraints = polyhedron.non_false_constraints(OldPoly),
> > +    UnchangedConstraints = list.filter(entailed(Varset, NewConstraints),
> > +         OldConstraints),
> > +    ( if    list.same_length(OldConstraints, UnchangedConstraints)
> > +      then  ChangeFlag = no
> > +      else  ChangeFlag = yes
> > +    ).
>
> How about:
>
> 	(
> 		some [OldConstraint] (
> 			member(OldConstraint, OldConstraints),
> 			\+ entailed(Varset, NewConstraints, OldConstraint)
> 		)
> 	->
> 		ChangeFlag = yes
> 	;
> 		ChangeFlag = no
> 	)
>
> This would perform a (green) cut at the first OldConstraint that was not
> entailed, rather than checking all of them.
>
Thanks, that's a much better way of doing it.


> > Index: compiler/term_constr_initial.m
> > ===================================================================
> > RCS file: compiler/term_constr_initial.m
> > diff -N compiler/term_constr_initial.m
> > --- /dev/null	1 Jan 1970 00:00:00 -0000
> > +++ compiler/term_constr_initial.m	24 Mar 2005 04:19:36 -0000
>
> > +%----------------------------------------------------------------------------%
> > +%
> > +% Process each predicate and set the termination property
> > +%
> > +
> > +% Sets termination to `cannot_loop' if:
> > +%   - there is a `terminates' pragma defined for the predicate.
> > +%   - there is a `check_termination' pragma defined for the predicate
> > +%     *and* the compiler is not currently generating the intermodule
> > +%     optimization file.
> > +%   - the predicate is builtin or compiler generated.  (These are assumed
> > +%     to terminate.
>
> Close parenthesis.
>
Done.

> > +%----------------------------------------------------------------------------%
> > +%
> > +% Set the argument size constraints for imported procedures.
> > +%
> > +
> > +% When interargument size constraints are imported from other modules there
> > +% are two parts.  The first of the these is a list of ints.  Each int
> > +% represents one of a procedures arguments (including typeinfo related ones).
>
> s/procedures/procedure's/
>
Fixed.

> > +:- pred process_imported_proc(proc_id::in, proc_table::in, proc_table::out)
> > +    is det.
> > +
> > +process_imported_proc(ProcId, !ProcTable) :-
> > +    some [!ProcInfo] (
> > +        !:ProcInfo = !.ProcTable ^ det_elem(ProcId),
> > +        proc_info_get_termination2_info(!.ProcInfo, TermInfo0),
>
> It would be better to test for import_headvarids = yes(HeadVarIds) here
> rather than below...
>
> > +        process_imported_term_info(!.ProcInfo, TermInfo0, TermInfo),
> > +        proc_info_set_termination2_info(TermInfo, !ProcInfo),
> > +        svmap.det_update(ProcId, !.ProcInfo, !ProcTable)
>
> ...because that would save updating the proc_info and proc_table
> unnecessarily.
>
Done.

> > +:- pred set_compiler_gen_terminates(pred_info::in, list(proc_id)::in,
> > +    pred_id::in, module_info::in, proc_table::in, proc_table::out)
> > +    is semidet.
> > +
> > +set_compiler_gen_terminates(PredInfo, ProcIds, PredId, ModuleInfo,
> > +        !ProcTable) :-
> > +    ( hlds_pred.pred_info_is_builtin(PredInfo) ->
> > +        set_builtin_terminates(ProcIds, PredId, PredInfo, ModuleInfo,
> > +            !ProcTable)
> > +    ;
> > +        (
> > +            Name  = pred_info_name(PredInfo),
> > +            Arity = pred_info_orig_arity(PredInfo),
> > +            special_pred_name_arity(SpecPredId0, Name, Arity),
> > +            ModuleName = pred_info_module(PredInfo),
> > +            any_mercury_builtin_module(ModuleName)
> > +        ->
> > +            SpecialPredId = SpecPredId0
> > +            ;
> > +            pred_info_get_origin(PredInfo, PredOrigin),
> > +            PredOrigin = special_pred(SpecialPredId - _)
> > +        )
> > +    ->
> > +        set_generated_terminates(ProcIds, SpecialPredId, ModuleInfo,
> > +            !ProcTable)
> > +    ;
> > +        fail
> > +    ).
>
> The above code needs some reformatting.
>
Done.


> > +    % Sets up the arg_size an termination info for those special preds
>
> s/an/and/
>
Done.  I've modified that comment so that it reads:

	% Sets the termination status and argument size information for
	% those special_preds (compare and index) where the arguments
	% are either zero sized or unconstrained in size.A

The existing comment didn't really make a great deal of sense.

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