Files
mercury/tools/binary
Zoltan Somogyi 5ad9a27793 Speed up the compiler's handling of code that constructs large ground terms
Estimated hours taken: 80
Branches: main

Speed up the compiler's handling of code that constructs large ground terms
by specializing the treatment of such code.

This diff reduces the compilation time for training_cars_full.m from 106.9
seconds to 30.3 seconds on alys, my laptop. The time on tools/speedtest
stays pretty much the same.

compiler/hlds_goal.m:
	Record the classification of from_ground_term scopes as purely
	constructing terms, purely deconstructing them or something other.

	Fix an old potential bug: variables inside the construct_how fields
	of unifications weren't being renamed along with other variables.
	This is a bug if any part of the compiler later looks at those
	variables. (I am not sure whether or not this happens.)

compiler/superhomogenous.m:
	Provisionally mark newly constructed static terms as being
	from_ground_term_construct. Mode checking will either confirm this
	or change the scope kind.

compiler/options.m:
compiler/handle_options.m:
	Add a new option, from_ground_term_threshold, that allows the user to
	set the boundary between ground terms that get scopes and ground terms
	do not. I plan to experiment with different settings later.

compiler/modes.m:
	Make this classification. For scopes that construct ground terms,
	use a specialized algorithm that avoids quadratic behavior.
	(It does not access the unify_inst_table, which is where the
	factor of N other than the length of the goal list came from.)
	The total size of the instmap_deltas, if printed out, still looks like
	O(N^2) in size, but due to structure sharing it needs only O(N) memory.

	For scopes that construct ground terms, set the determinism information
	so that det_analysis.m doesn't have to traverse such scopes.

	When handling disjunctions, check whether some nonlocals of the
	disjunctions are constructed by from_ground_term_construct scopes.
	For any such nonlocals, set their insts to just ground, throwing away
	the precise information we have about exactly what function symbols
	they and ALL their subterms are bound to. This is HUGE win, since
	it allows us avoid spending a lot of time building a huge merge_inst
	table, which later passes of the compiler (e.g. equiv_type_hlds) would
	then have to spend similarly huge times traversing.

	This approach does have a down side. If lots of arms of a disjunction
	bind a nonlocal to a large ground term, but a few bind it to a SMALL
	ground term, a term below the from_ground_term_threshold, this
	optimization won't kick in. That could be one purpose of the new
	option. It isn't documented yet; I will seek feedback about its
	usefulness first.

compiler/modecheck_unify.m:
	Handle the three different kinds of right hand sides separately.
	This yields a small speedup, because now we don't test rhs_vars and
	rhs_functors (the common right hand sides) for a special case
	(goals containing "any" insts) that is applicable only to
	rhs_lambda_goals.

compiler/unique_modes.m:
	Don't traverse scopes that construct ground terms, since modes.m has
	already done everything that needs to be done.

compiler/det_analysis.m:
	Don't traverse scopes that construct ground terms, since modes.m has
	already done the needed work.

compiler/instmap.m:
	Add a new predicate for use by modes.m.

	Many predicate names in this module were quite uninformative; give them
	informative names.

compiler/polymorphism.m:
	If this pass invalidates the from_ground_term_construct invariants,
	then mark the relevant scope as from_ground_term_other.

	Delete two unused access predicates.

compiler/equiv_type_hlds.m:
	Don't traverse scopes that construct ground terms, since modes.m
	ensures that their instmap deltas do not contain typed insts, and
	thus the scope cannot contain types that need to be expanded.

	Convert some predicates to single clauses.

compiler/goal_form.m:
compiler/goal_util.m:
	In predicates that test goals for various properties, don't traverse
	scopes that construct ground terms when the outcome of the test
	is the same for all such scopes.

	Convert some predicates to single clauses.

compiler/simplify.m:
	Do not look for common structs in from_ground_term_construct scopes,
	both because this speeds up the compiler, and because retaining
	references to ground terms is in fact a pessimization, not an
	optimization. This is because (a) those references need to be stored in
	stack slots across calls, and (b) the C code generators ensure that
	the cells representing ground terms will be shared as needed.

	If all arms of a switch are from_ground_term_construct scopes,
	do not merge the instmap_deltas from those arms, since this is
	both time-consuming (even after the other changes in this diff)
	and extremely unlikely to improve the instmap_delta.

	Disable common_struct in from_ground_term_construct scopes,
	since for these scopes, it is actually a pessimization.

	Do not delete from_ground_term_construct scopes, since many
	compiler passes can now use them.

	Do some manual deforestation, break up some large predicates,
	and give better names to some.

compiler/liveness.m
	Special-case the handling from_ground_term_construct scopes. This
	allows us to traverse them just once instead of three times, and this
	traversal is simpler and faster than any of the three.

	In some traversals, we were switching on the goal type twice; once
	in e.g. detect_liveness_in_goal_2, and once by calling
	goal_expr_has_subgoals. Eliminate the double switching by merging
	the relevant predicates. (The double-switching structure was easier
	to work with before we had multi-cons-id switches.)

compiler/typecheck.m:
	Move a lookup after a test, so we don't have to do it if the test
	fails.

	Provide a specialized mode for a predicate. This should allow the
	compiler to eliminate an argument and a test in the common case.

	Note a possible chance for a speedup.

compiler/typecheck_info.m:
	Don't apply empty substitutions to the types of a possibly very large
	set of variables.

compiler/quantification.m:
	Don't quantify from_ground_term_construct scopes. They are created
	correctly quantified, and any compiler pass that invalidates that
	quantification also removes the from_ground_term_construct mark.

	Don't apply empty renamings to a possibly very large set of variables.

	Move the code for handling scopes to its own predicate, to avoid
	overwhelming the code that handles other kinds of goals. Even from
	this, factor out the renaming code, since it is needed only for
	some kinds of scopes.

	Make some predicate names better reflect what the predicate does.

compiler/pd_cost.m:
	For from_ground_term_construct scopes, instead of computing their cost
	by adding up the costs of the goals inside, make their cost a constant,
	since binding a variable to a static term takes constant time.

compiler/pd_info.m:
	Add prefixes on field names to avoid ambiguities.

compiler/add_heap_ops.m:
compiler/add_trail_ops.m:
compiler/closure_analysis.m:
compiler/constraint.m:
compiler/cse_detection.m:
compiler/dead_proc_elim.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/delay_construct.m:
compiler/delay_partial_inst.m:
compiler/dep_par_conj.m:
compiler/distance_granularity.m:
compiler/exception_analysis.m:
compiler/follow_code.m:
compiler/follow_vars.m:
compiler/format_call.m:
compiler/granularity.m:
compiler/higher_order.m:
compiler/implicit_parallelism.m:
compiler/inlining.m:
compiler/interval.m:
compiler/lambda.m:
compiler/lco.m:
compiler/live_vars.m:
compiler/loop_inv.m:
compiler/middle_rec.m:
compiler/mode_util.m:
compiler/parallel_to_plain_conj.m:
compiler/saved_vars.m:
compiler/stm_expand.m:
compiler/store_alloc.m:
compiler/stratify.m:
compiler/structure_reuse.direct.detect_garbage.m:
compiler/structure_reuse.lbu.m:
compiler/structure_sharing.analysis.m:
compiler/switch_detection.analysis.m:
compiler/trail_analysis.m:
compiler/term_pass1.m:
compiler/tupling.m:
compiler/unneeded_code.m:
compiler/untupling.m:
compiler/unused_args.m:
	These passes have nothing to do in from_ground_term_construct scopes,
	so don't traverse them.

	In some modules (e.g. dead_proc_elim), some traversals had to be kept.

	In loop_inv.m, replace a code structure that updated accumulators
	with functions (which prevented the natural use of state variables),
	that in lots of places reconstructed the term it had just
	deconstructed, and obscured the identical handling of different kinds
	of goals, with a structure based on predicates, state variables and
	shared code for different goal types where possible.

	In store_alloc.m, avoid some double switching on the same value.

	In stratify.m, unneeded_code.m and unused_args.m, rename predicates
	to avoid ambiguities.

compiler/goal_path.m:
compiler/goal_util.m:
compiler/implementation_defined_literals.m:
compiler/intermode.m:
compiler/mark_static_terms.m:
compiler/ml_code_gen.m:
compiler/mode_ordering.m:
compiler/ordering_mode_constraints.m:
compiler/prop_mode_constraints.m:
compiler/purity.m:
compiler/rbmm.actual_region_arguments.m:
compiler/rbmm.add_rbmm_goal_infos.m:
compiler/rbmm.condition_renaming.m:
compiler/rbmm.execution_path.m:
compiler/rbmm.region_transformation.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/structure_reuse.indirect.m:
compiler/structure_reuse.lfu.m:
compiler/structure_reuse.versions.m:
compiler/term_const_build.m:
compiler/term_traversal.m:
compiler/unused_imports.m:
	Mark places where we cannot (yet) special case
	from_ground_term_construct scopes.

	In structure_reuse.lfu.m, turn nested if-then-elses into a switch in.

compiler/size_prof.m:
	Turn from_ground_term_construct scopes into from_ground_term_other
	scopes, since in term size profiling grades, we need to attach sizes to
	terms.

	Give predicates better names.

compiler/*.m:
	Minor changes to conform to the changes above.

compiler/make_hlds_passes.m:
	With -S, print statistics after the third pass over items, since
	this is the time-consuming one.

compiler/mercury_compile.m:
	Conform to the new names of some predicates.

	When declining to output a HLDS dump because it would be identical to
	the previous dump, don't confuse the user either by being silent about
	the decision, or by leaving an old dump laying around that could be
	mistaken for a new one.

tools/binary:
tools/binary_step:
	Bring these tools up to date.

compiler/Mmakefile:
	Add an int3s target for use by the new code in the tools. The
	Mmakefiles in the other directories with Mercury code already have
	such a target.

compiler/notes/allocation.html:
	Fix an out-of-date reference.

tests/debugger/polymorphic_ground_term.{m,inp,exp}:
	New test case to check whether liveness.m handles typeinfo liveness
	of ground terms correctly.

tests/debugger/Mmakefile:
	Enable the new test case.

tests/debugger/polymorphic_output.{m,exp}:
	Fix tab/space mixup.
2008-12-23 01:38:03 +00:00

811 lines
22 KiB
Bash
Executable File

#!/bin/sh
#
# vim: ts=4 sw=4 et
#
# This script finds miscompiled procedures.
#
# Given a stage2 directory that works (stage2.ok) and one that doesn't
# (stage2.bad), both of which must have their object files, this script
# uses binary search to try to find in stage2.bad first the C source file
# and then the module within that C source file that, when put together
# with everything else from the stage2.ok directory, still causes the
# compiler to fail.
#
# If the bad C source file has different numbers of modules in the bad and ok
# versions, then the script stops after identifying only the file.
#
# The test for the composite stage2 compiler is either bootstrap checking
# (the default), some initial part of bootstrap checking (making dependencies,
# compiling the library), the successful execution of all the test cases in
# one or more subdirectories of the tests directory, or the successful execution
# of a single command.
usage="\
Usage: $0 [options]
Options:
-b-, --no-bootcheck
Do not perform a bootcheck; check only the tests directory
or the single command.
-c, --compile-only
Check the successful creation of the stage3 .c files,
but do not compare stage2.ok and stage3.
-C, --compare-to-bad
Compile stage3 using the parameter settings in the stage2.bad
directory, and compare stage3 to stage2.bad, not stage2.ok.
-d, --dependency-only
Make dependencies for stage3 only. Do not compile stage3.
-D <dirname>, --dir <dirname>
Confine the search to one directory, library, mdbcomp
or compiler. (Usually useful only after a previous search.)
-f <modulename>, --file <modulename>
Confine the search to the named file(s).
(Usually useful only after a previous search.)
-h, --help
Display this usage message.
-j <num-jobs>, --jobs <num-jobs>
Run using <num-jobs> different parallel processes.
-l, --library-only
Check the successful creation of the stage3 .c files in the
library, but do not compile the compiler directory.
-m <mmake-args>, --mmake-args <mmake-args>
Pass <mmake-args> as options to \`mmake'.
-n, --negative-search
Look for the module that suppresses the bug, not causes it.
-o <filename>, --output-file <filename>
Output results to <filename>.
-r, --copy-runtime
Copy the runtime directory instead of linking it.
This is necessary if the test uses a compilation model option
that differs from the one used in the main runtime directory.
-s <command>, --single-command <command>
Execute the given command using each constructed compiler.
-t <testdir>, --test-dir <testdir>
Execute runtests from the named subdirectory of tests.
"
# If you change this, you will also need to change the files indicated
# in scripts/c2init.in.
STD_LIB_NAME=mer_std
set -x
bootcheck=""
compile_only=""
dependency_only=""
library_only=""
jfactor=
mmake_opts=""
outfile=""
copy_runtime=false
single_command=""
testdirs=""
negative=false
alldirs=""
allmodules=""
compare_to_bad=""
basis="ok"
while [ $# -gt 0 ]; do
case "$1" in
-b-|--no-bootcheck)
bootcheck="-b-" ;;
-c|--compile-only)
compile_only="-c" ;;
-C|--compare-to-bad)
compare_to_bad="-C"
basis="bad" ;;
-d|--dependency-only)
dependency_only="-d" ;;
-D|--dir)
if test "$alldirs" = ""
then
alldirs="$2"; shift
else
echo "You can specify only one directory." 1>&2
exit 1
fi
;;
-D*)
if test "$alldirs" = ""
then
alldirs="` expr $1 : '-d\(.*\)' `"
else
echo "You can specify only one directory." 1>&2
exit 1
fi
;;
-f|--file)
allmodules="$allmodules $2"; shift ;;
-f*)
allmodules="$allmodules ` expr $1 : '-f\(.*\)' `"; ;;
-h|--help)
echo "$usage"
exit 0 ;;
-j|--jobs)
jfactor="-j$2"; shift ;;
-j*)
jfactor="-j` expr $1 : '-j\(.*\)' `" ;;
--jobs*)
jfactor="--jobs` expr $1 : '--jobs\(.*\)' `" ;;
-l|--library-only)
library_only="-l" ;;
-m|--mmake)
mmake_opts="$mmake_opts $2"; shift ;;
-n|--negative-search)
negative=true ;;
-o|--output-file)
outfile="-o $2"; shift ;;
-o*)
outfile="-o ` expr $1 : '-o\(.*\)' `"; ;;
-r|--copy-runtime)
copy_runtime=true ;;
-s|--single-command)
single_command="$2"; shift ;;
-s*)
single_command=` expr "$1" : '-s\(.*\)' ` ;;
--single-command*)
single_command=` expr "$1" : '--single-command\(.*\)' ` ;;
-t|--test-dir)
testdirs="$testdirs -t$2"; shift ;;
-t*)
testdirs="$testdirs ` expr $1 : '-t\(.*\)' `" ;;
-*)
echo "$0: unknown option \`$1'" 1>&2
echo "$usage" 1>&2
exit 1 ;;
*)
echo "$usage" 1>&2
exit 1 ;;
esac
shift
done
if "$negative"
then
base=bad
trial=ok
expected=failure
else
base=ok
trial=bad
expected=success
fi
if test -d stage2.ok -a -d stage2.bad
then
echo "stage2.ok and stage2.bad both present"
else
echo "at least one of stage2.ok and stage2.bad is missing"
exit 1
fi
root=`/bin/pwd`
trueroot=`echo $root | sed '
s:/mount/munkora/mercury:/home/mercury:
s:/mount/munkora/home/mercury:/home/mercury:
s:/mount/munkora/clp/mercury:/home/mercury:'`
PATH=$root/tools:$PATH
export PATH
if test "$RMSTAGECMD" = ""
then
RMSTAGECMD="/bin/rm -fr"
fi
echo "starting at `date`"
for dir in $base $trial
do
for subdir in library mdbcomp compiler
do
case $subdir in
library) example_o=builtin.o ;;
mdbcomp) example_o=mdbcomp.prim_data.o ;;
compiler) example_o=check_hlds.cse_detection.o ;;
esac
if test -f stage2.$dir/$subdir/$example_o
then
echo "stage2.$dir/$subdir seems to have its object files"
else
echo "reconstructing object files in stage2.$dir/$subdir"
( cd stage2.$dir/$subdir; mmake )
fi
done
done
echo "starting binary at `date`"
set +x
[ -d stage2 ] || mkdir stage2
$RMSTAGECMD $trueroot/stage2/compiler < /dev/null &
$RMSTAGECMD $trueroot/stage2/library < /dev/null &
wait
$RMSTAGECMD $trueroot/stage2/* < /dev/null
echo linking stage 2... 1>&2
cd stage2
ln -s $root/main.c .
mkdir compiler
cd compiler
ln -s $root/compiler/[a-h]*.m .
ln -s $root/compiler/[i-o]*.m .
ln -s $root/compiler/[p-s]*.m .
ln -s $root/compiler/[t-z]*.m .
ln -s $root/compiler/*.pp .
cp $root/compiler/Mmake* .
cp $root/compiler/Mercury* .
cp $root/compiler/*FLAGS* .
cp $root/compiler/.mgnuc* .
cd $root/stage2
mkdir library
cd library
ln -s $root/library/[a-l]*.m .
ln -s $root/library/[m-z]*.m .
ln -s $root/library/*.init .
cp $root/library/print_extra_inits .
cp $root/library/Mmake* .
cp $root/library/Mercury* .
cp $root/library/*FLAGS* .
cp $root/library/.mgnuc* .
cd $root/stage2
mkdir mdbcomp
cd mdbcomp
ln -s $root/mdbcomp/*.m .
ln -s $root/mdbcomp/*.init .
cp $root/mdbcomp/Mmake* .
cp $root/mdbcomp/Mercury* .
cp $root/mdbcomp/*FLAGS* .
cp $root/mdbcomp/.mgnuc* .
cd $root/stage2
if "$copy_runtime"
then
mkdir runtime
cd runtime
ln -s $root/runtime/*.h .
ln -s $root/runtime/*.c .
ln -s $root/runtime/*.in .
ln -s $root/runtime/machdeps .
cp $root/runtime/Mmake* .
cd $root/stage2
else
# $root/runtime may be in a different grade from the stage2 directories.
ln -s $root/stage2.ok/runtime .
fi
ln -s $root/boehm_gc .
ln -s $root/browser .
ln -s $root/ssdb .
ln -s $root/trace .
ln -s $root/robdd .
ln -s $root/doc .
ln -s $root/scripts .
ln -s $root/util .
ln -s $root/profiler .
ln -s $root/deep_profiler .
ln -s $root/tools .
ln -s $root/conf* .
ln -s $root/aclocal.m4 .
ln -s $root/VERSION .
ln -s $root/Mercury.options .
ln -s $root/.*.in .
rm -f config*.log
cp $root/stage2.ok/Mmake* .
cd $root
# We don't copy the .d files. This prevents mmake from trying to remake any
# of the .c and .o files, which we provide in the form they should be used.
# cp stage2.ok/library/*.d stage2/library
cp stage2.ok/library/*.dep stage2/library
cp stage2.ok/library/*.dv stage2/library
cp stage2.ok/library/*.int0 stage2/library
cp stage2.ok/library/*.int3 stage2/library
cp stage2.ok/library/*.date3 stage2/library
cp stage2.ok/library/*.int stage2/library
cp stage2.ok/library/*.int2 stage2/library
cp stage2.ok/library/*.date stage2/library
cp stage2.ok/library/*.opt stage2/library
cp stage2.ok/library/*.optdate stage2/library
cp stage2.ok/library/*.trans_opt stage2/library
cp stage2.ok/library/*.trans_opt_date stage2/library
cp stage2.ok/library/*.mh stage2/library
# cp stage2.ok/mdbcomp/*.d stage2/mdbcomp
cp stage2.ok/mdbcomp/*.dep stage2/mdbcomp
cp stage2.ok/mdbcomp/*.dv stage2/mdbcomp
cp stage2.ok/mdbcomp/*.int0 stage2/mdbcomp
cp stage2.ok/mdbcomp/*.int3 stage2/mdbcomp
cp stage2.ok/mdbcomp/*.date3 stage2/mdbcomp
cp stage2.ok/mdbcomp/*.int stage2/mdbcomp
cp stage2.ok/mdbcomp/*.int2 stage2/mdbcomp
cp stage2.ok/mdbcomp/*.date stage2/mdbcomp
cp stage2.ok/mdbcomp/*.mh stage2/mdbcomp
# cp stage2.ok/compiler/*.d stage2/compiler
cp stage2.ok/compiler/*.dep stage2/compiler
cp stage2.ok/compiler/*.dv stage2/compiler
cp stage2.ok/compiler/*.int0 stage2/compiler
cp stage2.ok/compiler/*.int3 stage2/compiler
cp stage2.ok/compiler/*.date3 stage2/compiler
cp stage2.ok/compiler/*.int stage2/compiler
cp stage2.ok/compiler/*.int2 stage2/compiler
cp stage2.ok/compiler/*.date stage2/compiler
cp stage2.ok/compiler/*.mh stage2/compiler
if test "$bootcheck" = ""
then
cd $root
[ -d stage3 ] || mkdir stage3
$RMSTAGECMD $trueroot/stage3/compiler < /dev/null &
$RMSTAGECMD $trueroot/stage3/library < /dev/null &
wait
$RMSTAGECMD $trueroot/stage3/* < /dev/null
echo linking stage 3... 1>&2
cd stage3
ln -s $root/main.c
mkdir compiler
cd compiler
# Break up the links into several chunks.
# This is needed to cope with small limits
# on the size of argument vectors.
ln -s $root/compiler/[a-h]*.m .
ln -s $root/compiler/[i-o]*.m .
ln -s $root/compiler/[p-s]*.m .
ln -s $root/compiler/[t-z]*.m .
ln -s $root/compiler/*.pp .
cp $root/compiler/Mmake* .
cp $root/compiler/Mercury* .
cp $root/compiler/*FLAGS* .
cp $root/compiler/.mgnuc* .
cd $root/stage3
mkdir library
cd library
ln -s $root/library/[a-l]*.m .
ln -s $root/library/[m-z]*.m .
ln -s $root/library/*.init .
cp $root/library/Mercury* .
cp $root/library/*FLAGS* .
cp $root/library/.mgnuc* .
cp $root/library/Mmake* .
cd $root/stage3
mkdir mdbcomp
cd mdbcomp
ln -s $root/mdbcomp/*.m .
ln -s $root/mdbcomp/*.init .
cp $root/mdbcomp/Mercury* .
cp $root/mdbcomp/*FLAGS* .
cp $root/mdbcomp/.mgnuc* .
cp $root/mdbcomp/Mmake* .
cd $root/stage3
ln -s $root/boehm_gc .
ln -s $root/browser .
ln -s $root/ssdb .
ln -s $root/trace .
ln -s $root/doc .
ln -s $root/scripts .
ln -s $root/util .
ln -s $root/profiler .
ln -s $root/deep_profiler .
ln -s $root/runtime .
ln -s $root/tools .
ln -s $root/conf* .
ln -s $root/aclocal.m4 .
ln -s $root/VERSION .
ln -s $root/Mercury.options .
ln -s $root/.*.in .
rm -f config*.log
/bin/rm -f Mmake*
cp $root/stage2.$basis/Mmake* .
# cp $root/stage2.ok/so_locations .
cd $root
fi
set -x
if "$copy_runtime"
then
if (cd stage2 ; mmake $mmake_opts $jfactor runtime)
then
echo "building of stage 2 runtime successful"
else
echo "building of stage 2 runtime not successful"
exit 1
fi
fi
cp stage2.ok/main.o stage2
if test "$alldirs" = ""
then
echo testing which directory the problem is in
/bin/rm .stage2_problem
found=false
for testsubdir in library mdbcomp compiler
do
if $found
then
echo skipping test of $testsubdir
else
testsubdir_modules=`ls stage2.ok/$testsubdir`
anydiff=false
for testsubdir_module in $testsubdir_modules
do
if cmp -s stage2.{bad,ok}/$testsubdir/$testsubdir_module
then
true
else
anydiff=true
fi
done
if $anydiff
then
echo testing whether the problem is in $testsubdir
for subdir in library mdbcomp compiler
do
if test "$subdir" = "$testsubdir"
then
echo linking stage2/$subdir from stage2.bad/$subdir 1>&2
cp stage2.bad/$subdir/*.[co] stage2/$subdir
cp stage2.bad/$subdir/*.pic_o stage2/$subdir
else
echo linking stage2/$subdir from stage2.ok/$subdir 1>&2
cp stage2.ok/$subdir/*.[co] stage2/$subdir
cp stage2.ok/$subdir/*.pic_o stage2/$subdir
fi
done
binary_step $bootcheck $compile_only $compare_to_bad \
$dependency_only $library_only $jfactor -m "$mmake_opts" \
$outfile $testdirs -s "$single_command"
step_status=$?
if test -f .stage2_problem
then
echo could not build stage 2 to test
exit 1
fi
if "$negative"
then
if test "$step_status" == 0
then
testeddir=$testsubdir
found=true
echo "solution seems to be in the $testeddir directory"
fi
else
if test "$step_status" != 0
then
testeddir=$testsubdir
found=true
echo "problem seems to be in the $testeddir directory"
fi
fi
else
echo skipping $testsubdir: the two stage2s match
fi
fi
done
if test "$found" = false
then
echo "could not find problem"
exit 1
fi
else
for subdir in library mdbcomp compiler
do
echo linking stage2/$subdir from stage2.ok/$subdir 1>&2
cp stage2.ok/$subdir/*.[co] stage2/$subdir
cp stage2.ok/$subdir/*.pic_o stage2/$subdir
done
testeddir=$alldirs
if test ! -d stage2/$testeddir
then
echo $stage2/$testeddir does not exist
exit 1
fi
fi
# start out with all files in stage2 coming from stage2.$base
set +x
echo linking stage2 from stage2.$base 1>&2
cp stage2.$base/library/*.[co] stage2/library
cp stage2.$base/library/*.pic_o stage2/library
cp stage2.$base/compiler/*.[co] stage2/compiler
set -x
# find the set of candidate modules
if test "$allmodules" = ""
then
cd stage2/$testeddir
for module in *.c
do
if cmp -s $root/stage2.{bad,ok}/$testeddir/$module.c
then
true
else
allmodules="$allmodules `basename $module .c`"
fi
done
cd $root
else
for module in $allmodules
do
if test ! -f stage2/$testeddir/$module.c
then
echo $stage2/$testeddir/$module.c does not exist
exit 1
fi
done
fi
doubtful="$allmodules"
tested=`half $doubtful`
knowngood=
while test "$tested" != ""
do
# at this point, all the files in stage2 should be from stage2.$base
echo "doubtful modules: $doubtful"
echo "testing modules: $tested"
for module in $tested
do
cp stage2.$trial/$testeddir/$module.[co] stage2/$testeddir
if test $testeddir = library
then
cp stage2.$trial/library/$module.pic_o stage2/library
fi
done
if "$negative"
then
if binary_step $bootcheck $compile_only $compare_to_bad $dependency_only $library_only $jfactor -m "$mmake_opts" $outfile $testdirs -s "$single_command"
then
echo "test succeeded"
lasttest=success
doubtful="$tested"
else
echo "test failed"
lasttest=failure
set +x
newdoubtful=""
for module in $doubtful
do
if not appears $module $tested
then
newdoubtful="$newdoubtful $module"
fi
done
set -x
doubtful="$newdoubtful"
fi
else
if binary_step $bootcheck $compile_only $compare_to_bad $dependency_only $library_only $jfactor -m "$mmake_opts" $outfile $testdirs -s "$single_command"
then
echo "test succeeded"
lasttest=success
knowngood="$knowngood $tested"
set +x
newdoubtful=""
for module in $doubtful
do
if not appears $module $tested
then
newdoubtful="$newdoubtful $module"
fi
done
set -x
doubtful="$newdoubtful"
else
echo "test failed"
lasttest=failure
doubtful="$tested"
fi
fi
for module in $tested
do
cp stage2.$base/$testeddir/$module.[co] stage2/$testeddir
if test $testeddir = library
then
cp stage2.$base/library/$module.pic_o stage2/library
fi
done
tested=`half $doubtful`
if test "$tested" = "" -a "$lasttest" = "$expected"
then
tested="$doubtful"
fi
done
if test "$doubtful" = ""
then
echo "cannot find the problem; all modules behave as expected"
exit 1
fi
module=`echo $doubtful | tr -d ' '`
if "$negative"
then
true
else
echo "the modules known to be ok are: $knowngood"
fi
echo "there is a problem in $testeddir/$module"
echo
basecnt=`egrep '^MR_END_MODULE' stage2.$base/$testeddir/$module.c | wc -l`
trialcnt=`egrep '^MR_END_MODULE' stage2.$trial/$testeddir/$module.c | wc -l`
if test $basecnt -ne $trialcnt
then
basecnt=`echo $basecnt | tr -d ' '`
trialcnt=`echo $trialcnt | tr -d ' '`
echo "the two versions of the problem module"
echo "differ in the number of C modules they have"
echo "$base version: $basecnt vs $trial version: $trialcnt"
exit 1
fi
for dir in $base $trial
do
cd stage2.$dir/$testeddir
divide $module.c $basecnt
cd $root
done
set +x
doubtful=
knowngood=
i=0
while test $i -le $basecnt
do
# If two corresponding parts from stage2.ok and stage.bad are the same,
# then the bug cannot be in that part.
if cmp -s stage2.$base/$testeddir/$module.c.part.$i stage2.$trial/$testeddir/$module.c.part.$i
then
knowngood="$knowngood $i"
else
doubtful="$doubtful $i"
fi
i=`expr $i + 1`
done
set -x
tested=`half $doubtful`
/bin/rm -fr .stage2_problem
while test "$tested" != ""
do
echo "knowngood: $knowngood"
echo "doubtful: $doubtful"
echo "testing: $tested"
assemble $base $trial $testeddir $module $basecnt $tested
cd stage2/$testeddir
/bin/rm $module.o
mmake $module.o
cd $root
if "$negative"
then
if binary_step $bootcheck $compile_only $compare_to_bad $dependency_only $library_only $jfactor -m "$mmake_opts" $outfile $testdirs -s "$single_command"
then
echo "test succeeded"
lasttest=success
doubtful="$tested"
else
echo "test failed"
if test -f .stage2_problem
then
/bin/rm .stage2_problem
echo "problem with the creation of stage 2:"
echo "search of $testeddir/$module abandoned"
exit 1
fi
lasttest=failure
set +x
newdoubtful=""
for part in $doubtful
do
if not appears $part $tested
then
newdoubtful="$newdoubtful $part"
fi
done
set -x
doubtful="$newdoubtful"
fi
else
if binary_step $bootcheck $compile_only $compare_to_bad $dependency_only $library_only $jfactor -m "$mmake_opts" $outfile $testdirs -s "$single_command"
then
echo "test succeeded"
lasttest=success
knowngood="$knowngood $tested"
set +x
newdoubtful=""
for part in $doubtful
do
if not appears $part $tested
then
newdoubtful="$newdoubtful $part"
fi
done
set -x
doubtful="$newdoubtful"
else
echo "test failed"
if test -f .stage2_problem
then
/bin/rm .stage2_problem
echo "problem with the creation of stage 2:"
echo "search of $testeddir/$module abandoned"
exit 1
fi
lasttest=failure
doubtful="$tested"
fi
fi
tested=`half $doubtful`
if test "$tested" = "" -a "$lasttest" = "$expected"
then
tested="$doubtful"
fi
done
if test "$doubtful" = ""
then
echo "cannot find the problem; all parts behave as expected"
exit 1
fi
doubtful=`echo $doubtful | tr -d ' '`
if "$negative"
then
true
else
echo "the parts known to be ok are: $knowngood"
fi
echo "there is a problem in $testeddir/$module.c.part.$doubtful"
echo "the difference is:"
echo
diff -u stage2.$base/$testeddir/$module.c.part.$doubtful stage2.$trial/$testeddir/$module.c.part.$doubtful
echo
echo "finishing at `date`"
exit 0