[m-rev.] diff: implement concat_string_list for .NET

Fergus Henderson fjh at cs.mu.OZ.AU
Fri Feb 21 17:44:33 AEDT 2003


Even though this patch doesn't completely solve the problem,
I think it is a step on the way, so unless anyone has any
objections, I will go ahead and commit this.

On 18-Feb-2003, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> On 18-Feb-2003, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> > I'm currently testing a patch which fixes both of these problems.
> 
> Unfortunately that still didn't do the trick -- loop hoisting still
> doesn't hoist the calls to string__length.  However, with the patch
> below, these calls are now present in the input to loop hoisting,
> so I think it ought to be able to optimize them.  I think the problem
> may perhaps be related to the fact that they occur at the start of the
> `then' part of an if-then-else, rather than before the `if'.
> 
> Ralph, would you mind having a look at this?
> How about modifying the loop_inv pass so that it treats goals at the start
> of an if-then-else condition up to and including the first can_fail goal
> the same way it treats goals in a conjunction?
> 
> ----------
> 
> Estimated hours taken: 1
> Branches: main
> 
> compiler/mercury_compile.m:
> compiler/notes/compiler_design.html:
> 	Perform loop invariant hoisting after inlining, since inlining
> 	can create opportunities for loop invariant hoisting.
> 
> library/string.m:
> 	Implement string__index in Mercury, in terms of string__length,
> 	string__unsafe_index, and a new procedure string__index_check,
> 	rather than implementing in C.  string__index_check contains
> 	just the index checking code from the old string__index implementation.
> 	Implementing string__index in Mercury like this should allow the
> 	Mercury compiler to do loop invariant hoisting on the calls to
> 	string__length.
> 
> 	Declare the output argument for string__unsafe_index
> 	and string__index_det with mode `uo', to match string__index.
> 	For unsafe__index, this change was needed now that string__index is
> 	implemented in terms of string__unsafe_index.
> 
> Workspace: /home/ceres/fjh/mercury
> Index: compiler/mercury_compile.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
> retrieving revision 1.274
> diff -u -d -r1.274 mercury_compile.m
> --- compiler/mercury_compile.m	16 Feb 2003 02:16:36 -0000	1.274
> +++ compiler/mercury_compile.m	18 Feb 2003 00:51:59 -0000
> @@ -10,6 +10,8 @@
>  % This is the top-level of the Mercury compiler.
>  
>  % This module invokes the different passes of the compiler as appropriate.
> +% The constraints on pass ordering are documented in
> +% compiler/notes/compiler_design.html.
>  
>  %-----------------------------------------------------------------------------%
>  
> @@ -53,13 +55,13 @@
>  :- import_module transform_hlds__lambda.
>  :- import_module backend_libs__type_ctor_info, transform_hlds__termination.
>  :- import_module transform_hlds__higher_order, transform_hlds__accumulator.
> -:- import_module transform_hlds__inlining, transform_hlds__deforest.
> +:- import_module transform_hlds__inlining, transform_hlds__loop_inv.
> +:- import_module transform_hlds__deforest.
>  :- import_module aditi_backend__dnf, aditi_backend__magic.
>  :- import_module transform_hlds__dead_proc_elim.
>  :- import_module transform_hlds__delay_construct, transform_hlds__unused_args.
>  :- import_module transform_hlds__unneeded_code, transform_hlds__lco.
>  :- import_module ll_backend__deep_profiling.
> -:- import_module transform_hlds__loop_inv.
>  
>  	% the LLDS back-end
>  :- import_module ll_backend__saved_vars, ll_backend__stack_opt.
> @@ -1924,14 +1926,14 @@
>  			Verbose, Stats, HLDS33),
>  	mercury_compile__maybe_dump_hlds(HLDS33, "33", "accum"),
>  
> -	% Hoisting loop invariants first invokes pass 34, "mark_static".
> +	mercury_compile__maybe_do_inlining(HLDS33, Verbose, Stats, HLDS34),
> +	mercury_compile__maybe_dump_hlds(HLDS34, "34", "inlining"),
> +
> +	% Hoisting loop invariants first invokes pass 35, "mark_static".
>  	% "mark_static" is also run at stage 60.
>  	%
> -	mercury_compile__maybe_loop_inv(HLDS33, Verbose, Stats, HLDS35),
> -	mercury_compile__maybe_dump_hlds(HLDS35, "35", "loop_inv"),
> -
> -	mercury_compile__maybe_do_inlining(HLDS35, Verbose, Stats, HLDS36),
> -	mercury_compile__maybe_dump_hlds(HLDS36, "36", "inlining"),
> +	mercury_compile__maybe_loop_inv(HLDS34, Verbose, Stats, HLDS36),
> +	mercury_compile__maybe_dump_hlds(HLDS36, "36", "loop_inv"),
>  
>  	mercury_compile__maybe_deforestation(HLDS36, Verbose, Stats, HLDS37),
>  	mercury_compile__maybe_dump_hlds(HLDS37, "37", "deforestation"),
> @@ -2902,7 +2904,7 @@
>  			%
>  		mercury_compile__maybe_mark_static_terms(HLDS0, Verbose, Stats,
>  			HLDS1),
> -		mercury_compile__maybe_dump_hlds(HLDS1, "34", "mark_static"),
> +		mercury_compile__maybe_dump_hlds(HLDS1, "35", "mark_static"),
>  
>  		maybe_write_string(Verbose,
>  			"% Hoisting loop invariants...\n"),
> Index: compiler/notes/compiler_design.html
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/notes/compiler_design.html,v
> retrieving revision 1.81
> diff -u -d -r1.81 compiler_design.html
> --- compiler/notes/compiler_design.html	10 Jan 2003 10:45:02 -0000	1.81
> +++ compiler/notes/compiler_design.html	18 Feb 2003 00:50:15 -0000
> @@ -619,38 +619,30 @@
>  
>  <li> inlining (i.e. unfolding) of simple procedures (inlining.m)
>  
> -<li> deforestation and partial evaluation (deforest.m). This optimizes
> -  multiple traversals of data structures within a conjunction, and
> -  avoids creating intermediate data structures. It also performs
> -  loop unrolling where the clause used is known at compile time.
> -  deforest.m makes use of the following sub-modules
> -  (`pd_' stands for "partial deduction"):
> -  <ul>
> -  <li>
> -  constraint.m transforms goals so that goals which can fail
> -  are executed earlier.
> -  <li>
> -  pd_cost.m contains some predicates to estimate the improvement
> -  caused by deforest.m.
> -  <li>
> -  pd_debug.m produces debugging output.
> -  <li>
> -  pd_info.m contains a state type for deforestation.
> -  <li>
> -  pd_term.m contains predicates to check that the deforestation algorithm
> -  terminates.
> -  <li>
> -  pd_util.m contains various utility predicates.
> -  </ul>
> -
>  <li> loop_inv.m: loop invariant hoisting.  This transformation moves
>    computations within loops that are the same on every iteration to the outside
>    of the loop so that the invariant computations are only computed once.  The
>    transformation turns a single looping predicate containing invariant
>    computations into two: one that computes the invariants on the first
>    iteration and then loops by calling the second predicate with extra arguments
> -  for the invariant values.
> - 
> +  for the invariant values.  This pass should come after inlining, since
> +  inlining can expose important opportunities for loop invariant hoisting.
> +  Such opportunities might not be visible before inlining because only
> +  *part* of the body of a called procedure is loop-invariant.
> +
> +<li> deforestation and partial evaluation (deforest.m). This optimizes
> +  multiple traversals of data structures within a conjunction, and
> +  avoids creating intermediate data structures. It also performs
> +  loop unrolling where the clause used is known at compile time.
> +  deforest.m makes use of the following sub-modules (`pd_' stands for
> +  "partial deduction"): <ul> <li> constraint.m transforms goals so that
> +  goals which can fail are executed earlier.  <li> pd_cost.m contains
> +  some predicates to estimate the improvement caused by deforest.m.
> +  <li> pd_debug.m produces debugging output.  <li> pd_info.m contains
> +  a state type for deforestation.  <li> pd_term.m contains predicates
> +  to check that the deforestation algorithm terminates.  <li> pd_util.m
> +  contains various utility predicates.  </ul>
> +
>  <li> issue warnings about unused arguments from predicates, and create
>  specialized versions without them (unused_args.m); type_infos are often unused.
>  
> Index: library/string.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/library/string.m,v
> retrieving revision 1.193
> diff -u -d -r1.193 string.m
> --- library/string.m	13 Feb 2003 17:24:31 -0000	1.193
> +++ library/string.m	18 Feb 2003 01:55:01 -0000
> @@ -257,7 +257,7 @@
>  
>  :- func string__index_det(string, int) = char.
>  :- pred string__index_det(string, int, char).
> -:- mode string__index_det(in, in, out) is det.
> +:- mode string__index_det(in, in, uo) is det.
>  %	string__index_det(String, Index, Char):
>  %	`Char' is the (`Index' + 1)-th character of `String'.
>  %	Calls error/1 if `Index' is out of range (negative, or greater than or
> @@ -269,7 +269,7 @@
>  
>  :- func string__unsafe_index(string, int) = char.
>  :- pred string__unsafe_index(string, int, char).
> -:- mode string__unsafe_index(in, in, out) is det.
> +:- mode string__unsafe_index(in, in, uo) is det.
>  %	string__unsafe_index(String, Index, Char):
>  %	`Char' is the (`Index' + 1)-th character of `String'.
>  %	WARNING: behavior is UNDEFINED if `Index' is out of range
> @@ -693,8 +693,10 @@
>  	char__digit_to_int(Char, M),
>  	M < Base.
>  
> -
> -
> +% It's important to inline string__index and string__index_det.
> +% so that the compiler can do loop invariant hoisting
> +% on calls to string__length that occur in loops.
> +:- pragma inline(string__index_det/3).
>  string__index_det(String, Int, Char) :-
>  	( string__index(String, Int, Char0) ->
>  		Char = Char0
> @@ -3000,72 +3002,78 @@
>  		int::in, int::in) is semidet.
>  
>  string__contains_char(Str, Char, Index, Length) :-
> -	Index < Length,
> -	string__unsafe_index(Str, Index, IndexChar),
> -	( IndexChar = Char ->
> -		true
> +	( Index < Length ->
> +		string__unsafe_index(Str, Index, IndexChar),
> +		( IndexChar = Char ->
> +			true
> +		;
> +			string__contains_char(Str, Char, Index + 1, Length)
> +		)
>  	;
> -		string__contains_char(Str, Char, Index + 1, Length)
> +		fail
>  	).
>  
>  /*-----------------------------------------------------------------------*/
>  
> -/*
> -:- pred string__index(string, int, char).
> -:- mode string__index(in, in, out) is semidet.
> -*/
> -:- pragma foreign_proc("C", string__index(Str::in, Index::in, Ch::uo),
> -		[will_not_call_mercury, promise_pure, thread_safe], "
> -
> -                /*
> -		** We do not test for negative values of Index
> -                ** because (a) MR_Word is unsigned and hence a
> -                ** negative argument will appear as a very large
> -                ** positive one after the cast and (b) anybody
> -                ** dealing with the case where strlen(Str) > MAXINT
> -                ** is clearly barking mad (and one may well
> -                ** get an integer overflow error in this case).
> -                */
> +/* :- pred string__index(string, int, char). */
> +/* :- mode string__index(in, in, out) is semidet. */
> +% It's important to inline string__index and string__index_det.
> +% so that the compiler can do loop invariant hoisting
> +% on calls to string__length that occur in loops.
> +:- pragma inline(string__index/3).
> +string__index(Str, Index, Char) :-
> +	Len = string__length(Str),
> +	( string__index_check(Index, Len) ->
> +		string__unsafe_index(Str, Index, Char)
> +	;
> +		fail
> +	).
>  
> -	if ((MR_Unsigned) Index >= strlen(Str)) {
> -		SUCCESS_INDICATOR = MR_FALSE;
> -	} else {
> -		SUCCESS_INDICATOR = MR_TRUE;
> -		Ch = Str[Index];
> -	}
> +:- pred string__index_check(int, int).
> +:- mode string__index_check(in, in) is semidet.
> +:- pragma promise_pure(string__index_check/2).
> +/* We should consider making this routine a compiler built-in. */
> +:- pragma foreign_proc("C", string__index_check(Index::in, Length::in),
> +		[will_not_call_mercury, promise_pure, thread_safe],
> +"
> +	/*
> +	** We do not test for negative values of Index
> +	** because (a) MR_Unsigned is unsigned and hence a
> +	** negative argument will appear as a very large
> +	** positive one after the cast and (b) anybody
> +	** dealing with the case where strlen(Str) > MAXINT
> +	** is clearly barking mad (and one may well
> +	** get an integer overflow error in this case).
> +	*/
> +	SUCCESS_INDICATOR = ((MR_Unsigned) Index < (MR_Unsigned) Length);
>  ").
> -:- pragma foreign_proc("MC++", string__index(Str::in, Index::in, Ch::uo),
> +:- pragma foreign_proc("MC++", string__index_check(Index::in, Length::in),
>  		[will_not_call_mercury, promise_pure, thread_safe], "
> -	if (Index < 0 || Index >= Str->get_Length()) {
> -		SUCCESS_INDICATOR = MR_FALSE;
> -	} else {
> -		SUCCESS_INDICATOR = MR_TRUE;
> -		Ch = Str->get_Chars(Index);
> -	}
> +	SUCCESS_INDICATOR = ((MR_Unsigned) Index < (MR_Unsigned) Length);
>  ").
> -string__index(Str, Index, Char) :-
> -	string__first_char(Str, First, Rest),
> -	( Index = 0 ->
> -		Char = First
> -	;
> -		string__index(Rest, Index - 1, Char)
> -	).
> +string__index_check(Index, Length) :-
> +	Index >= 0,
> +	Index < Length.
>  
>  /*-----------------------------------------------------------------------*/
>  
>  :- pragma foreign_proc("C", 
> -	string__unsafe_index(Str::in, Index::in, Ch::out),
> +	string__unsafe_index(Str::in, Index::in, Ch::uo),
>  		[will_not_call_mercury, promise_pure, thread_safe], "
>  	Ch = Str[Index];
>  ").
>  :- pragma foreign_proc("MC++", 
> -	string__unsafe_index(Str::in, Index::in, Ch::out),
> +	string__unsafe_index(Str::in, Index::in, Ch::uo),
>  		[will_not_call_mercury, promise_pure, thread_safe], "
>  	Ch = Str->get_Chars(Index);
>  ").
>  string__unsafe_index(Str, Index, Char) :-
> -	( string__index(Str, Index, IndexChar) ->
> -		Char = IndexChar
> +	( string__first_char(Str, First, Rest) ->
> +		( Index = 0 ->
> +			Char = First
> +		;
> +			string__unsafe_index(Rest, Index - 1, Char)
> +		)
>  	;
>  		error("string__unsafe_index: out of bounds")
>  	).

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
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