[m-dev.] diff: inlining c_code bug fixes

Fergus Henderson fjh at cs.mu.OZ.AU
Wed May 17 17:17:46 AEST 2000


This diff fixes bug B6 in the list I posted the other day:

	(B6) XXX `pragma c_code' & nondet & --inlining

The comments I've added to the code below explain the problem in
a bit more detail:

+       % For the MLDS back-end, don't inline any pragma c codes.
+       % XXX This is a work-around needed because of some problems
+       % with the current MLDS back-end implementation of
+       % pragma c_code.  In particular, ml_elim_nested.m assumes
+       % that target_code instructions don't contain variables,
+       % but with the current implementation sometimes they do.
+       % Also ml_code_gen.m doesn't handle complicated pragma_c_code
+       % goals, which can result from inlining.

With this diff, I think the MLDS back-end should bootcheck
even with intermodule optimization enabled, i.e. just
using `tools/bootcheck --grade hlc.gc', with nothing
special in Mmake.stage.params.

----------

Estimated hours taken: 2

Fix a bug in the LLDS back-end where it would inline nondet `pragma c_code'
procedures if the user used a `pragma inline' declaration, and
then subsequently get a software error during code generation.

For the MLDS back-end, don't inline `pragma c_code' goals,
since that causes problems with the current implementation
of `pragma c_code'.

compiler/inlining.m:
	Move the code to test for nondet `pragma c_code' from
	inlining__mark_predproc to inlining__should_inline_proc,
	since testing for it in the former doesn't guarantee
	that it won't be inlined.  Likewise for `aditi_memo'.

	For the MLDS back-end, don't inline any `pragma c_code'
	goals.  This required adding a new bool to the
	`inline_params' and `inlining_info' structs, to hold
	the value of the --high-level-code variable.

	Change the `inline_params' structure to use field names.

library/Mmakefile:
	Delete an earlier work-around for the MLDS inlining problem,
	since with the better work-around mentioned above,
	is no longer needed.

tests/hard_coded/Mmakefile:
tests/hard_coded/inline_nondet_pragma_c.m:
tests/hard_coded/inline_nondet_pragma_c.exp:
	A regression test for the bug fix described above.

Workspace: /home/pgrad/fjh/ws/hg2
Index: compiler/inlining.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/inlining.m,v
retrieving revision 1.84
diff -u -d -r1.84 inlining.m
--- compiler/inlining.m	1999/10/25 03:48:59	1.84
+++ compiler/inlining.m	2000/05/17 06:31:03
@@ -147,10 +147,16 @@
 
 %-----------------------------------------------------------------------------%
 
-:- type inline_params	--->	params(bool, bool, int, int, int).
-				% simple, single_use,
-				%	size-threshold, simple-goal-threshold
-				%		var-threshold
+	% this structure holds option values, extracted from the globals
+:- type inline_params
+	--->	params(
+			simple				:: bool,
+			single_use			:: bool,
+			size_threshold			:: int,
+			simple_goal_threshold		:: int,
+			var_threshold			:: int,
+			highlevel_code			:: bool
+		).
 
 inlining(ModuleInfo0, ModuleInfo) -->
 		%
@@ -166,6 +172,7 @@
 		%   we want in procedures - if inlining a procedure
 		%   would cause the number of variables to exceed
 		%   this threshold then we don't inline it.
+		% - whether we're in an MLDS grade
 		%
 	globals__io_lookup_bool_option(inline_simple, Simple),
 	globals__io_lookup_bool_option(inline_single_use, SingleUse),
@@ -173,8 +180,9 @@
 							CompoundThreshold),
 	globals__io_lookup_int_option(inline_simple_threshold, SimpleThreshold),
 	globals__io_lookup_int_option(inline_vars_threshold, VarThreshold),
+	globals__io_lookup_bool_option(highlevel_code, HighLevelCode),
 	{ Params = params(Simple, SingleUse, CompoundThreshold,
-			SimpleThreshold, VarThreshold) },
+			SimpleThreshold, VarThreshold, HighLevelCode) },
 
 		%
 		% Get the usage counts for predicates
@@ -232,11 +240,17 @@
 		io__state, io__state).
 :- mode inlining__mark_predproc(in, in, in, in, in, out, di, uo) is det.
 
+%
+% This predicate effectively adds implicit `pragma inline'
+% directives for procedures that match its heuristic.
+%
+
 inlining__mark_predproc(PredProcId, NeededMap, Params, ModuleInfo, 
 		InlinedProcs0, InlinedProcs) -->
 	(
 		{ Params = params(Simple, SingleUse, CompoundThreshold,
-				SimpleThreshold, _VarThreshold) },
+				SimpleThreshold, _VarThreshold,
+				_HighLevelCode) },
 		{ PredProcId = proc(PredId, ProcId) },
 		{ module_info_pred_info(ModuleInfo, PredId, PredInfo) },
 		{ pred_info_procedures(PredInfo, Procs) },
@@ -265,18 +279,9 @@
 			{ NumUses = 1 }
 		),
 		% Don't inline recursive predicates
-		{ \+ goal_calls(CalledGoal, PredProcId) },
-
-		% Under no circumstances inline model_non pragma c codes.
-		% The resulting code would not work properly.
-		\+ {
-			CalledGoal = pragma_c_code(_,_,_,_,_,_,_) - _,
-			proc_info_interface_code_model(ProcInfo, model_non)
-		},
+		% (unless explicitly requested)
+		{ \+ goal_calls(CalledGoal, PredProcId) }
 
-		% Don't inline memoed Aditi predicates.
-		{ pred_info_get_markers(PredInfo, Markers) },
-		{ \+ check_marker(Markers, aditi_memo) }
 	->
 		inlining__mark_proc_as_inlined(PredProcId, ModuleInfo,
 			InlinedProcs0, InlinedProcs)
@@ -364,6 +369,7 @@
 :- type inline_info	
 	---> inline_info(
 		int,			% variable threshold for inlining
+		bool,			% highlevel_code option
 		set(pred_proc_id),	% inlined procs
 		module_info,		% module_info
 		list(tvar),		% universally quantified type vars
@@ -392,8 +398,9 @@
 
 inlining__in_predproc(PredProcId, InlinedProcs, Params,
 		ModuleInfo0, ModuleInfo, IoState0, IoState) :-
-	Params = params(_Simple, _SingleUse, _CompoundThreshold,
-			_SimpleThreshold, VarThresh),
+	VarThresh = Params^var_threshold,
+	HighLevelCode = Params^highlevel_code,
+
 	PredProcId = proc(PredId, ProcId),
 
 	module_info_preds(ModuleInfo0, PredTable0),
@@ -412,13 +419,13 @@
 
 	DetChanged0 = no,
 
-	InlineInfo0 = inline_info(
-		VarThresh, InlinedProcs, ModuleInfo0, UnivQTVars, Markers,
+	InlineInfo0 = inline_info(VarThresh, HighLevelCode,
+		InlinedProcs, ModuleInfo0, UnivQTVars, Markers,
 		VarSet0, VarTypes0, TypeVarSet0, TypeInfoVarMap0, DetChanged0),
 
 	inlining__inlining_in_goal(Goal0, Goal, InlineInfo0, InlineInfo),
 
-	InlineInfo = inline_info(_, _, _, _, _, VarSet, VarTypes, TypeVarSet, 
+	InlineInfo = inline_info(_, _, _, _, _, _, VarSet, VarTypes, TypeVarSet, 
 		TypeInfoVarMap, DetChanged),
 
 	pred_info_set_typevarset(PredInfo0, TypeVarSet, PredInfo1),
@@ -484,14 +491,14 @@
 inlining__inlining_in_goal(call(PredId, ProcId, ArgVars, Builtin, Context,
 		Sym) - GoalInfo0, Goal - GoalInfo, InlineInfo0, InlineInfo) :-
 
-	InlineInfo0 = inline_info(VarThresh, InlinedProcs, ModuleInfo,
-		HeadTypeParams, Markers,
+	InlineInfo0 = inline_info(VarThresh, HighLevelCode,
+		InlinedProcs, ModuleInfo, HeadTypeParams, Markers,
 		VarSet0, VarTypes0, TypeVarSet0, TypeInfoVarMap0, DetChanged0),
 
 	% should we inline this call?
 	(
 		inlining__should_inline_proc(PredId, ProcId, Builtin,
-				InlinedProcs, Markers, ModuleInfo),
+			HighLevelCode, InlinedProcs, Markers, ModuleInfo),
 			% okay, but will we exceed the number-of-variables
 			% threshold?
 		varset__vars(VarSet0, ListOfVars),
@@ -531,8 +538,8 @@
 		TypeInfoVarMap = TypeInfoVarMap0,
 		DetChanged = DetChanged0
 	),
-	InlineInfo = inline_info(
-		VarThresh, InlinedProcs, ModuleInfo, HeadTypeParams, Markers,
+	InlineInfo = inline_info(VarThresh, HighLevelCode,
+		InlinedProcs, ModuleInfo, HeadTypeParams, Markers,
 		VarSet, VarTypes, TypeVarSet, TypeInfoVarMap, DetChanged).
 
 inlining__inlining_in_goal(generic_call(A, B, C, D) - GoalInfo,
@@ -721,18 +728,21 @@
 
 	% Check to see if we should inline a call.
 	%
-	% Fails if the called predicate is a builtin or is imported.
+	% Fails if the called predicate cannot be inlined,
+	% e.g. because it is a builtin, we don't have code for it,
+	% it uses nondet pragma c_code, etc.
 	%
-	% Succeeds if the called predicate has an annotation
-	% indicating that it should be inlined, or if the goal
-	% is a conjunction of builtins.
+	% It succeeds if the called procedure is inlinable,
+	% and in addition either there was a `pragma inline'
+	% for this procedure, or the procedure was marked by
+	% inlining__mark_predproc as having met its heuristic.
 
 :- pred inlining__should_inline_proc(pred_id, proc_id, builtin_state,
-	set(pred_proc_id), pred_markers, module_info).
-:- mode inlining__should_inline_proc(in, in, in, in, in, in) is semidet.
+	bool, set(pred_proc_id), pred_markers, module_info).
+:- mode inlining__should_inline_proc(in, in, in, in, in, in, in) is semidet.
 
-inlining__should_inline_proc(PredId, ProcId, BuiltinState, InlinedProcs,
-		CallingPredMarkers, ModuleInfo) :-
+inlining__should_inline_proc(PredId, ProcId, BuiltinState, HighLevelCode,
+		InlinedProcs, CallingPredMarkers, ModuleInfo) :-
 
 	% don't inline builtins, the code generator will handle them
 
@@ -763,6 +773,33 @@
 	% not to inline.
 
 	\+ pred_info_requested_no_inlining(PredInfo),
+
+	% For the LLDS back-end,
+	% under no circumstances inline model_non pragma c codes.
+	% The resulting code would not work properly.
+	proc_info_goal(ProcInfo, CalledGoal),
+	\+ (
+		HighLevelCode = no,
+		CalledGoal = pragma_c_code(_,_,_,_,_,_,_) - _,
+		proc_info_interface_code_model(ProcInfo, model_non)
+	),
+
+	% For the MLDS back-end, don't inline any pragma c codes.
+	% XXX This is a work-around needed because of some problems
+	% with the current MLDS back-end implementation of
+	% pragma c_code.  In particular, ml_elim_nested.m assumes
+	% that target_code instructions don't contain variables,
+	% but with the current implementation sometimes they do.
+	% Also ml_code_gen.m doesn't handle complicated pragma_c_code
+	% goals, which can result from inlining.
+	\+ (
+		HighLevelCode = yes,
+		CalledGoal = pragma_c_code(_,_,_,_,_,_,_) - _
+	),
+
+	% Don't inline memoed Aditi predicates.
+	pred_info_get_markers(PredInfo, CalledPredMarkers),
+	\+ check_marker(CalledPredMarkers, aditi_memo),
 
 	% Don't inline Aditi procedures into non-Aditi procedures,
 	% since this could result in joins being performed by
Index: library/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/library/Mmakefile,v
retrieving revision 1.46
diff -u -d -r1.46 Mmakefile
--- library/Mmakefile	2000/05/13 13:53:36	1.46
+++ library/Mmakefile	2000/05/17 05:09:57
@@ -23,18 +23,6 @@
 MCFLAGS-int = --no-halt-at-warn
 
 #-----------------------------------------------------------------------------#
-#
-# XXX The MLDS back-end has a bug which causes problems when inlining
-# pragma c_code into nondet procedures.  This works around those problems.
-#
-
-ifneq "$(findstring hlc,$(GRADE))" ""
-    MCFLAGS-benchmarking = --no-inlining
-    MCFLAGS-std_util = --no-inlining
-    MCFLAGS-term_io = --no-inlining
-endif
-
-#-----------------------------------------------------------------------------#
 
 # If we're going to generate both `.o' files and `.pic_o' files, then
 # don't remove the intermediate `.c' files.
Index: tests/hard_coded/inline_nondet_pragma_c.exp
===================================================================
RCS file: inline_nondet_pragma_c.exp
diff -N inline_nondet_pragma_c.exp
--- /dev/null	Thu Mar 30 14:06:13 2000
+++ inline_nondet_pragma_c.exp	Wed May 17 16:43:05 2000
@@ -0,0 +1,2 @@
+[10, 20, 42, 99]
+[1 - (10 - 1), 1 - (10 - 2), 1 - (20 - 1), 1 - (20 - 2), 1 - (42 - 1), 1 - (42 - 2), 1 - (99 - 1), 1 - (99 - 2), 2 - (10 - 1), 2 - (10 - 2), 2 - (20 - 1), 2 - (20 - 2), 2 - (42 - 1), 2 - (42 - 2), 2 - (99 - 1), 2 - (99 - 2)]
Index: tests/hard_coded/inline_nondet_pragma_c.m
===================================================================
RCS file: inline_nondet_pragma_c.m
diff -N inline_nondet_pragma_c.m
--- /dev/null	Thu Mar 30 14:06:13 2000
+++ inline_nondet_pragma_c.m	Wed May 17 16:42:02 2000
@@ -0,0 +1,49 @@
+
+:- module inline_nondet_pragma_c.
+:- interface.
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+:- import_module std_util.
+
+main -->
+	{ solutions(foo, FooList) },
+	print(FooList), nl,
+	{ solutions(bar, List) },
+	print(List), nl.
+
+:- pred bar(pair(int, pair(int, int))::out) is multi.
+bar(X - (Y - Z)) :-
+	( X = 1 ; X = 2),
+	foo(Y),
+	( Z = 1 ; Z = 2).
+	
+%
+% This example implements the equivalent of
+%     foo(X) :- X = 20 ; X = 10 ; X = 42 ; X = 99 ; fail.
+%
+:- pred foo(int).
+:- mode foo(out) is multi.
+:- pragma inline(foo/1).
+:- pragma c_code(foo(X::out), [will_not_call_mercury, thread_safe],
+     local_vars("
+	     int state;
+     "),
+     first_code("
+	     LOCALS->state = 1;
+     "),
+     retry_code("
+	     LOCALS->state++;
+     "),
+     common_code("
+	     switch (LOCALS->state) {
+		     case 1: X = 20; SUCCEED; break;
+		     case 2: X = 10; SUCCEED; break;
+		     case 3: X = 42; SUCCEED; break;
+		     case 4: X = 99; SUCCEED; break;
+		     case 5: FAIL; break;
+	     }
+     ")
+).
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.84
diff -u -d -r1.84 Mmakefile
--- tests/hard_coded/Mmakefile	2000/05/09 10:48:48	1.84
+++ tests/hard_coded/Mmakefile	2000/05/17 06:43:26
@@ -66,6 +66,7 @@
 	impossible_unify \
 	impure_prune \
 	integer_test \
+	inline_nondet_pragma_c \
 	merge_and_remove_dups \
 	minint_bug \
 	mode_choice \

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list