[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