[m-dev.] for review: a replacement of code_exprn.m

Zoltan Somogyi zs at cs.mu.OZ.AU
Mon Sep 4 16:09:08 AEDT 2000


This is the diff I am committing. Due to its stricter self-checks, the new
compiler gets a compile-time abort on tests/hard_coded/typeclasses/type_spec.m
if you compile that test in a debug grade. The reason is an incorrect
instmap_delta annotation on a goal constructed by type specialization;
Simon is looking into it. I am not holding up the commit because a compile
time abort is better than silent generation of possibly incorrect code.

Zoltan.

Estimated hours taken: 140

Add an alternative to code_exprn that does eager code generation (code_exprn
always does lazy code generation). Its main advantages are that the new code
is significantly simpler, and that it does not generate unnecessary shuffling
code. Its main disadvantage, which is that it does not eliminate the creation
of unneeded cells, can be eliminated by switching on --unneeded-code.

For now, you can select the use of the new code generator with the
--no-lazy-code option (which was previously present but unused).
This will be made the default later, after I do more performance tests.

Var_locn contains stricter self-checks than code_exprn does. This required
modifications to some other parts of the code generator to ensure that the
self-checks do not fail unnecessarily. (This mostly took the form of explicitly
killing off dead variables before calling code_info__clear_all_registers, which
would complain about losing the last record of the value of a variable that was
alive as far as it knew.) To make my changes simpler, also took the opportunity
to simplify parts of the code generator which were handing around rvals that
in fact had to be wrappers around lvals, by handing around the lvals directly.

Testing this change also required fixing an old bug which prevented compiling
the library with -O1 --trace deep, together with the usual intermodule
optimization. The bug is that a library module reads predicates from
builtin.opt or private_builtin.opt, does not eliminate them because of the -O1,
and then tries to generate traced code for them. However, this fails because
the builtin modules contain some predicates that cannot be made to conform to
typeinfo-liveness, which is required by tracing.

compiler/var_locn.m:
	The new module that implements eager code generation.

compiler/follow_vars.m:
	Improve the follow_vars pass, since eager code generation requires
	better follow_vars information. We now generate correct information
	for generic calls, and record not only where some vars (e.g. those
	which appear as input arguments of following calls) should be put,
	but also which registers are not reserved for those variables and
	are thus available for other variables.

compiler/hlds_goal.m:
	Modify the follow_vars field of the goal_info to record the number
	of the first non-reserved register.

compiler/code_info.m:
 	Replace the general-purpose predicate code_info__cache_exprn, which
	associated a variable with an rval without generating code, with a set
	of special-purpose predicates such as code_info__assign_const_to_var
	and code_info__assign_cell_to_var, some of which can generate code.

	These new predicates and some older ones (e.g. code_info__setup_call)
	now choose at runtime whether to call code_exprn or var_locn. The
	basis for the decision is checking whether the code_info structure
	contains an exprn_info or a var_locn_info. This is decided in
	code_info__init based on the value of the lazy_code option, and
	maintained unchanged from then on.

	Rename some predicates to better reflect their current possible
	behaviors.

compiler/unify_gen.m:
	Call the new special-purpose predicates in code_info instead of
	code_info__cache_exprn.

	Replace an incorrect clause with a call to error, since that clause
	could never be invoked.

compiler/call_gen.m:
	Hand over the task of generating the args of generic calls to
	code_info, since it already has code to do the right thing, which
	includes reserving the registers to be used for the input args.

	Notify the rest of the code generator after the last use of
	non-forward-live variables, in order to avoid spurious calls to error
	(it is an error to clobber the last location of a live variable).

	Notify the rest of the code generator when generic calls overwrite
	registers, to allow the proper consistency checks to be made.

	If an output variable is singleton, then do not make it known to the
	code generator. It never will never become dead, and may thus cause a
	spurious compiler abort if its storage is ever clobbered.

	Export a predicate for use by follow_vars.

	Factor out some common code.

	Call the new preds in code_info where necessary.

compiler/pragma_c_gen.m:
	Notify the rest of the code generator after the last use of
	non-forward-live variables, in order to avoid spurious calls to error
	(it is an error to clobber the last location of a live variable).

	If an output variable is singleton, then do not make it known to the
	code generator. It never will never become dead, and may thus cause a
	spurious compiler abort if its storage is ever clobbered.

	When using var_locn, ensure that none of the input arguments of a
	model_semi pragma_c_code is assigned to r1. If we did, and the last
	reference to the value of that argument was after an assignment to
	SUCCESS_INDICATOR, the C compiler would be forced to generate code
	to shuffle the value of the argument out of the way.

compiler/code_exprn.m:
	Minor changes to return lvals directly instead of lvals wrapped inside
	rvals and to conform the new format of follow_vars.

	Do not include the registers reserved by follow_vars in the
	search for a spare register.

compiler/lookup_switch.m:
compiler/switch_gen.m:
	Fix an old bug that did not matter with code_exprn but does matter with
	var_locn: the branch end structure was being computed in the wrong
	place.

compiler/disj_gen.m:
	At the ends of non-last disjuncts, kill off the variables that we
	needed to know inside the disjunct but won't need to know after the
	disjunct, in order to avoid error messages about throwing away their
	state. The variables affected are those which are needed only by the
	resumption point of the next disjunct, not by enclosing resumption
	points or forward execution.

compiler/arg_info.m:
	Associate an lval, not an rval, with each argument.

compiler/*.m:
	Minor changes to conform to (a) the new format of follow_vars, (b)
	the replacement of rvals containing lvals by lvals.

compiler/code_util.m:	
	Add some utility predicates for var_locn.m.

compiler/exprn_aux.m:	
	Add some utility functions for var_locn.m.

	Export a predicate for var_locn.m.

compiler/handle_options.m:
	If --no-lazy-code is set, switch on the "optimizations" on whose
	presence it depends.

compiler/mercury_compile.m:
compiler/code_gen.m:
	Turn off tracing for predicates that don't obey typeinfo liveness
	for backend_by_preds and backend_by_phases respectively.

	Look up options in the globals structure in the module_info, not in the
	globals structure in the I/O state, since this is where we turn off
	tracing. (We should later make sure that other parts of the compiler
	are also consistent on this issue.)

compiler/stack_layout.m:
	Throw away any continuation_info structures that belong to predicates
	that originate in a builtin module.

Index: compiler/arg_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/arg_info.m,v
retrieving revision 1.32
diff -u -b -r1.32 arg_info.m
--- compiler/arg_info.m	1999/06/01 09:43:32	1.32
+++ compiler/arg_info.m	2000/07/17 06:04:49
@@ -33,7 +33,7 @@
 	% Given a list of the head variables and their argument information,
 	% return a list giving the input variables and their initial locations.
 :- pred arg_info__build_input_arg_list(assoc_list(prog_var, arg_info),
-	assoc_list(prog_var, rval)).
+	assoc_list(prog_var, lval)).
 :- mode arg_info__build_input_arg_list(in, out) is det.
 
 %-----------------------------------------------------------------------------%
@@ -174,11 +174,9 @@
 arg_info__build_input_arg_list([], []).
 arg_info__build_input_arg_list([V - Arg | Rest0], VarArgs) :-
 	Arg = arg_info(Loc, Mode),
-	(
-		Mode = top_in
-	->
+	( Mode = top_in ->
 		code_util__arg_loc_to_register(Loc, Reg),
-		VarArgs = [V - lval(Reg) | VarArgs0]
+		VarArgs = [V - Reg | VarArgs0]
 	;
 		VarArgs = VarArgs0
 	),
Index: compiler/call_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/call_gen.m,v
retrieving revision 1.142
diff -u -b -r1.142 call_gen.m
--- compiler/call_gen.m	2000/08/08 04:44:33	1.142
+++ compiler/call_gen.m	2000/08/17 11:16:45
@@ -19,38 +19,39 @@
 :- interface.
 
 :- import_module prog_data, hlds_pred, hlds_goal, llds, code_info.
-:- import_module list, set, assoc_list.
+:- import_module list, assoc_list.
 
-:- pred call_gen__generate_generic_call(code_model, generic_call,
-			list(prog_var), list(mode), determinism,
-			hlds_goal_info, code_tree, code_info, code_info).
-:- mode call_gen__generate_generic_call(in, in, in, in, in, in,
-			out, in, out) is det.
-
-:- pred call_gen__generate_call(code_model, pred_id, proc_id, list(prog_var),
-			hlds_goal_info, code_tree, code_info, code_info).
-:- mode call_gen__generate_call(in, in, in, in, in, out, in, out) is det.
-
-:- pred call_gen__generate_builtin(code_model, pred_id, proc_id, list(prog_var),
-			code_tree, code_info, code_info).
-:- mode call_gen__generate_builtin(in, in, in, in, out, in, out) is det.
-
-:- pred call_gen__partition_args(assoc_list(prog_var, arg_info),
-						list(prog_var), list(prog_var)).
-:- mode call_gen__partition_args(in, out, out) is det.
-
-:- pred call_gen__input_arg_locs(assoc_list(prog_var, arg_info), 
-				assoc_list(prog_var, arg_loc)).
-:- mode call_gen__input_arg_locs(in, out) is det.
-
-:- pred call_gen__output_arg_locs(assoc_list(prog_var, arg_info), 
-				assoc_list(prog_var, arg_loc)).
-:- mode call_gen__output_arg_locs(in, out) is det.
-
-:- pred call_gen__save_variables(set(prog_var), code_tree,
-						code_info, code_info).
-:- mode call_gen__save_variables(in, out, in, out) is det.
+:- pred call_gen__generate_call(code_model::in, pred_id::in, proc_id::in,
+	list(prog_var)::in, hlds_goal_info::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+:- pred call_gen__generate_generic_call(code_model::in, generic_call::in,
+	list(prog_var)::in, list(mode)::in, determinism::in,
+	hlds_goal_info::in, code_tree::out, code_info::in, code_info::out)
+	is det.
+
+:- pred call_gen__generate_builtin(code_model::in, pred_id::in, proc_id::in,
+	list(prog_var)::in, code_tree::out, code_info::in, code_info::out)
+	is det.
+
+:- pred call_gen__maybe_remove_aditi_state_args(generic_call::in,
+	list(prog_var)::in, list(type)::in, list(mode)::in,
+	list(prog_var)::out, list(type)::out, list(mode)::out) is det.
+
+	% call_gen__generic_call_info(CodeModel, GenericCall,
+	% 	CodeAddr, FirstImmediateInputReg).
+:- pred call_gen__generic_call_info(code_model::in, generic_call::in,
+	code_addr::out, assoc_list(prog_var, arg_info)::out, int::out) is det.
 
+:- pred call_gen__partition_args(assoc_list(prog_var, arg_info)::in,
+	list(prog_var)::out, list(prog_var)::out) is det.
+
+:- pred call_gen__input_arg_locs(assoc_list(prog_var, arg_info)::in,
+	assoc_list(prog_var, arg_loc)::out) is det.
+
+:- pred call_gen__output_arg_locs(assoc_list(prog_var, arg_info)::in,
+	assoc_list(prog_var, arg_loc)::out) is det.
+
 %---------------------------------------------------------------------------%
 
 :- implementation.
@@ -58,22 +59,22 @@
 :- import_module hlds_module, hlds_data, code_util, builtin_ops, rl.
 :- import_module arg_info, type_util, mode_util, unify_proc, instmap.
 :- import_module polymorphism, trace, globals, options.
-:- import_module std_util, bool, int, tree, map.
+:- import_module std_util, bool, int, tree, map, set.
 :- import_module varset, require, string.
 
 %---------------------------------------------------------------------------%
 
-call_gen__generate_call(CodeModel, PredId, ModeId, Arguments, GoalInfo, Code)
+call_gen__generate_call(CodeModel, PredId, ProcId, Arguments, GoalInfo, Code)
 		-->
 
 		% Find out which arguments are input and which are output.
-	code_info__get_pred_proc_arginfo(PredId, ModeId, ArgInfo),
+	code_info__get_pred_proc_arginfo(PredId, ProcId, ArgInfo),
 	{ assoc_list__from_corresponding_lists(Arguments, ArgInfo, ArgsInfos) },
 
 		% Save the known variables on the stack, except those
 		% generated by this call.
 	{ call_gen__select_out_args(ArgsInfos, OutArgs) },
-	call_gen__save_variables(OutArgs, SaveCode),
+	code_info__save_variables(OutArgs, SaveCode),
 
 		% Save possibly unknown variables on the stack as well
 		% if they may be needed on backtracking, and figure out the
@@ -91,25 +92,9 @@
 	call_gen__generate_call_vn_livevals(InputArguments, OutArgs,
 		LiveCode),
 
-		% Figure out what variables will be live at the return point,
-		% and where, for use in the accurate garbage collector, and
-		% in the debugger.
-	code_info__get_instmap(InstMap),
-	{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
-	{ instmap__apply_instmap_delta(InstMap, InstMapDelta, ReturnInstMap) },
-	{ call_gen__output_arg_locs(ArgsInfos, OutputArgLocs) },
-		% We must update the code generator state to reflect
-		% the situation after the call before building
-		% the return liveness info. No later code in this
-		% predicate depends on the old state.
-	call_gen__rebuild_registers(ArgsInfos),
-	code_info__generate_return_live_lvalues(OutputArgLocs, ReturnInstMap,
-		ReturnLiveLvalues),
-
 		% Make the call.
 	code_info__get_module_info(ModuleInfo),
-
-	code_info__make_entry_label(ModuleInfo, PredId, ModeId, yes, Address),
+	code_info__make_entry_label(ModuleInfo, PredId, ProcId, yes, Address),
 	code_info__get_next_label(ReturnLabel),
 	{ call_gen__call_comment(CodeModel, CallComment) },
 	{ goal_info_get_context(GoalInfo, Context) },
@@ -121,6 +106,19 @@
 			- "continuation label"
 	]) },
 
+		% Figure out what variables will be live at the return point,
+		% and where, for use in the accurate garbage collector, and
+		% in the debugger.
+	code_info__get_instmap(InstMap),
+	{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
+	{ instmap__apply_instmap_delta(InstMap, InstMapDelta, ReturnInstMap) },
+
+		% Update the code generator state to reflect the situation
+		% after the call.
+	call_gen__handle_return(ArgsInfos, ReturnInstMap, ReturnLiveLvalues),
+
+		% If the call can fail, generate code to check for and
+		% handle the failure.
 	call_gen__handle_failure(CodeModel, FailHandlingCode),
 
 	{ Code =
@@ -147,44 +145,33 @@
 call_gen__generate_generic_call(_OuterCodeModel, GenericCall, Args0,
 		Modes0, Det, GoalInfo, Code) -->
 	list__map_foldl(code_info__variable_type, Args0, Types0),
+	{ call_gen__maybe_remove_aditi_state_args(GenericCall,
+		Args0, Types0, Modes0, Args, Types, Modes) },
 
-	{ GenericCall = aditi_builtin(aditi_tuple_insert_delete(_, _), _) ->
-		% Remove the `aditi__state' argument and its type-info from
-		% the tuple to insert or delete. This must be done after
-		% mode analysis (so that removal of the `aditi__state' does
-		% not stuff up the argument numbers in error messages).
-		% Here is as good a place as any.
-		get_state_args_det(Types0, TupleTypes, _, _),
-		call_gen__remove_tuple_state_arg(TupleTypes,
-			Args0, Args),
-		call_gen__remove_tuple_state_arg(TupleTypes,
-			Types0, Types),
-		call_gen__remove_tuple_state_arg(TupleTypes,
-			Modes0, Modes)
-	;
-		Args = Args0,
-		Types = Types0,
-		Modes = Modes0
-	},
-
 	{ determinism_to_code_model(Det, CodeModel) },
 	code_info__get_module_info(ModuleInfo),
 	{ make_arg_infos(Types, Modes, CodeModel, ModuleInfo, ArgInfos) },
 	{ assoc_list__from_corresponding_lists(Args, ArgInfos, ArgsInfos) },
 	{ call_gen__partition_args(ArgsInfos, InVars, OutVars) },
 	{ set__list_to_set(OutVars, OutArgs) },
-	call_gen__save_variables(OutArgs, SaveCode),
+	code_info__save_variables(OutArgs, SaveCode),
 
 	call_gen__prepare_for_call(CodeModel, FlushCode, CallModel),
 
 	{ call_gen__generic_call_info(CodeModel, GenericCall,
-		CodeAddr, FirstInput) },
+		CodeAddr, SpecifierArgInfos, FirstImmInput) },
+
+		% Place the immediate input arguments and the part of the
+		% called-code-specifier determined by variables in their
+		% registers.
+	{ call_gen__give_vars_consecutive_regs(InVars, FirstImmInput, InLocs) },
+	{ call_gen__give_vars_consecutive_arg_infos(InVars, FirstImmInput,
+		top_in, InVarArgInfos) },
+	{ list__append(SpecifierArgInfos, InVarArgInfos, InArgInfos) },
+	code_info__setup_call(InArgInfos, caller, ImmediateCode),
 
-		% place the immediate input arguments in registers
-	call_gen__generate_immediate_args(InVars, FirstInput,
-		InLocs, ImmediateCode),
 	code_info__generate_call_stack_vn_livevals(OutArgs, LiveVals0),
-	{ call_gen__extra_livevals(FirstInput, ExtraLiveVals) },
+	{ call_gen__extra_livevals(FirstImmInput, ExtraLiveVals) },
 	{ set__insert_list(LiveVals0, ExtraLiveVals, LiveVals1) },
 	{ set__insert_list(LiveVals1, InLocs, LiveVals) },
 
@@ -193,8 +180,8 @@
 	;
 		FirstOutput = 1
 	},
-	{ call_gen__outvars_to_outargs(OutVars, FirstOutput, OutArguments) },
-	{ call_gen__output_arg_locs(OutArguments, OutputArgLocs) },
+	{ call_gen__give_vars_consecutive_arg_infos(OutVars, FirstOutput,
+		top_out, OutArgsInfos) },
 
 	code_info__get_instmap(InstMap),
 	{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
@@ -203,18 +190,12 @@
 		% Doing this after generating the immediate input arguments,
 		% results in slightly more efficient code by not moving
 		% the immediate arguments twice.
-	call_gen__generic_call_setup(GenericCall, InVars, OutVars, SetupCode),
+	call_gen__generic_call_nonvar_setup(GenericCall, InVars, OutVars,
+		SetupCode),
 
 	trace__prepare_for_call(TraceCode),
 
-		% We must update the code generator state to reflect
-		% the situation after the call before building
-		% the return liveness info. No later code in this
-		% predicate depends on the old state.
-	call_gen__rebuild_registers(OutArguments),
-	code_info__generate_return_live_lvalues(OutputArgLocs, ReturnInstMap,
-		ReturnLiveLvalues),
-
+		% Make the call.
 	code_info__get_next_label(ReturnLabel),
 	{ goal_info_get_context(GoalInfo, Context) },
 	{ CallCode = node([
@@ -227,6 +208,13 @@
 			- "Continuation label"
 	]) },
 
+		% Update the code generator state to reflect the situation
+		% after the call.
+	call_gen__handle_return(OutArgsInfos, ReturnInstMap,
+		ReturnLiveLvalues),
+
+		% If the call can fail, generate code to check for and
+		% handle the failure.
 	call_gen__handle_failure(CodeModel, FailHandlingCode),
 
 	{ Code =
@@ -239,8 +227,29 @@
 		     FailHandlingCode))))))
 	}.
 
-:- pred call_gen__remove_tuple_state_arg(list(type), list(T), list(T)).
-:- mode call_gen__remove_tuple_state_arg(in, in, out) is det.
+call_gen__maybe_remove_aditi_state_args(GenericCall, Args0, Types0, Modes0,
+		Args, Types, Modes) :-
+	( GenericCall = aditi_builtin(aditi_tuple_insert_delete(_, _), _) ->
+		% Remove the `aditi__state' argument and its type-info from
+		% the tuple to insert or delete. This must be done after
+		% mode analysis (so that removal of the `aditi__state' does
+		% not stuff up the argument numbers in error messages).
+		% Here is as good a place as any.
+		get_state_args_det(Types0, TupleTypes, _, _),
+		call_gen__remove_tuple_state_arg(TupleTypes,
+			Args0, Args),
+		call_gen__remove_tuple_state_arg(TupleTypes,
+			Types0, Types),
+		call_gen__remove_tuple_state_arg(TupleTypes,
+			Modes0, Modes)
+	;
+		Args = Args0,
+		Types = Types0,
+		Modes = Modes0
+	).
+
+:- pred call_gen__remove_tuple_state_arg(list(type)::in, list(T)::in,
+	list(T)::out) is det.
 
 call_gen__remove_tuple_state_arg(TupleTypes, Args0, Args) :-
 	get_state_args_det(Args0, OtherArgs0, State0Arg, StateArg),
@@ -258,14 +267,12 @@
 	list__append(OtherArgs, [State0Arg, StateArg], Args).
 
 	% The registers before the first input argument are all live.
-:- pred call_gen__extra_livevals(int, list(lval)).
-:- mode call_gen__extra_livevals(in, out) is det.
+:- pred call_gen__extra_livevals(int::in, list(lval)::out) is det.
 
 call_gen__extra_livevals(FirstInput, ExtraLiveVals) :-
 	call_gen__extra_livevals(1, FirstInput, ExtraLiveVals). 
 
-:- pred call_gen__extra_livevals(int, int, list(lval)).
-:- mode call_gen__extra_livevals(in, in, out) is det.
+:- pred call_gen__extra_livevals(int::in, int::in, list(lval)::out) is det.
 
 call_gen__extra_livevals(Reg, FirstInput, ExtraLiveVals) :-
 	( Reg < FirstInput ->
@@ -276,23 +283,19 @@
 		ExtraLiveVals = []
 	).
 
-	% call_gen__generic_call_info(CodeModel, GenericCall,
-	% 	CodeAddr, FirstImmediateInputReg).
-:- pred call_gen__generic_call_info(code_model, generic_call, code_addr, int).
-:- mode call_gen__generic_call_info(in, in, out, out) is det.
-
-call_gen__generic_call_info(_, higher_order(_, _, _), do_call_closure, 4).
-call_gen__generic_call_info(_, class_method(_, _, _, _),
-		do_call_class_method, 5).
+call_gen__generic_call_info(_, higher_order(PredVar, _, _),
+		do_call_closure, [PredVar - arg_info(1, top_in)], 4).
+call_gen__generic_call_info(_, class_method(TCVar, _, _, _),
+		do_call_class_method, [TCVar - arg_info(1, top_in)], 5).
 call_gen__generic_call_info(CodeModel, aditi_builtin(aditi_call(_,_,_,_),_),
-		CodeAddr, 5) :-
+		CodeAddr, [], 5) :-
 	( CodeModel = model_det, CodeAddr = do_det_aditi_call
 	; CodeModel = model_semi, CodeAddr = do_semidet_aditi_call
 	; CodeModel = model_non, CodeAddr = do_nondet_aditi_call
 	).
 call_gen__generic_call_info(CodeModel,
 		aditi_builtin(aditi_tuple_insert_delete(InsertDelete, _), _),
-		CodeAddr, 5) :-
+		CodeAddr, [], 5) :-
 	( InsertDelete = insert, CodeAddr = do_aditi_insert
 	; InsertDelete = delete, CodeAddr = do_aditi_delete
 	),
@@ -301,15 +304,14 @@
 call_gen__generic_call_info(CodeModel,
 		aditi_builtin(
 			aditi_insert_delete_modify(InsertDelMod, _, _), _),
-		CodeAddr, FirstReg) :-
+		CodeAddr, [], FirstReg) :-
 	call_gen__aditi_insert_delete_modify_info(InsertDelMod,
 		CodeAddr, FirstReg),
 	require(unify(CodeModel, model_det),
 		"aditi_insert_delete_modify not model_det").
 
-:- pred call_gen__aditi_insert_delete_modify_info(aditi_insert_delete_modify,
-		code_addr, int).
-:- mode call_gen__aditi_insert_delete_modify_info(in, out, out) is det.
+:- pred call_gen__aditi_insert_delete_modify_info(
+	aditi_insert_delete_modify::in, code_addr::out, int::out) is det.
 
 call_gen__aditi_insert_delete_modify_info(bulk_insert,
 		do_aditi_bulk_insert, 3).
@@ -321,68 +323,54 @@
 	error("Sorry, not yet implemented: aditi_modify(filter)").
 call_gen__aditi_insert_delete_modify_info(modify(bulk),
 		do_aditi_bulk_modify, 3).
+
+	% Some of the values that generic call passes to the dispatch routine
+	% to specify what code is being indirectly called come from HLDS
+	% variables, while the others come from constants. The ones that come
+	% from variables (the closure for a higher order call, the
+	% typeclass_info for a method call) are set up together with the
+	% arguments being passed the indirectly called code, since with eager
+	% code generation this ensures that each target register is reserved
+	% for the variable destined for it. This is set up by
+	% call_gen__generic_call_info. call_gen__generic_call_nonvar_setup
+	% generates code to pass to the dispatch routine the parts of the
+	% indirectly called code's identifier that come from constants.
 
-	% Produce code to set up the arguments to a generic call
-	% that are always present, such as the closure for a higher-order call,
-	% the typeclass_info for a class method call or the relation
-	% name for an Aditi update operation.
-:- pred call_gen__generic_call_setup(generic_call, list(prog_var),
-	list(prog_var), code_tree, code_info, code_info).
-:- mode call_gen__generic_call_setup(in, in, in, out, in, out) is det.
-
-call_gen__generic_call_setup(higher_order(PredVar, _, _),
-		InVars, OutVars, SetupCode) -->
-	call_gen__place_generic_call_var(PredVar, "closure", PredVarCode),
+:- pred call_gen__generic_call_nonvar_setup(generic_call::in,
+	list(prog_var)::in, list(prog_var)::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+call_gen__generic_call_nonvar_setup(higher_order(_, _, _),
+		InVars, OutVars, Code) -->
+	code_info__clobber_regs([reg(r, 2), reg(r, 3)]),
 	{ list__length(InVars, NInVars) },
 	{ list__length(OutVars, NOutVars) },
-	{ NumArgCode = node([
+	{ Code = node([
 		assign(reg(r, 2), const(int_const(NInVars))) -
 			"Assign number of immediate input arguments",
 		assign(reg(r, 3), const(int_const(NOutVars))) -
 			"Assign number of output arguments"
-	]) },
-	{ SetupCode = tree(PredVarCode, NumArgCode) }.
-call_gen__generic_call_setup(class_method(TCVar, Method, _, _),
-		InVars, OutVars, SetupCode) -->
-	call_gen__place_generic_call_var(TCVar, "typeclass_info", TCVarCode),
+	]) }.
+call_gen__generic_call_nonvar_setup(class_method(_, Method, _, _),
+		InVars, OutVars, Code) -->
+	code_info__clobber_regs([reg(r, 2), reg(r, 3), reg(r, 4)]),
 	{ list__length(InVars, NInVars) },
 	{ list__length(OutVars, NOutVars) },
-	{ ArgsCode = node([
+	{ Code = node([
 		assign(reg(r, 2), const(int_const(Method))) -
 			"Index of class method in typeclass info",
 		assign(reg(r, 3), const(int_const(NInVars))) -
 			"Assign number of immediate input arguments",
 		assign(reg(r, 4), const(int_const(NOutVars))) -
 			"Assign number of output arguments"
-	]) },
-	{ SetupCode = tree(TCVarCode, ArgsCode) }.
-call_gen__generic_call_setup(aditi_builtin(Builtin, _),
-		InVars, OutVars, SetupCode) -->
-	call_gen__aditi_builtin_setup(Builtin, InVars, OutVars,
-		SetupCode).
-
-:- pred call_gen__place_generic_call_var(prog_var, string, code_tree,
-		code_info, code_info).
-:- mode call_gen__place_generic_call_var(in, in, out, in, out) is det.
-
-call_gen__place_generic_call_var(Var, Description, Code) -->
-	code_info__produce_variable(Var, VarCode, VarRVal),
-	{ VarRVal = lval(reg(r, 1)) ->
-               CopyCode = empty
-	;
-	       % We don't need to clear r1 first - the arguments
-	       % should have been moved into their proper positions and
-	       % all other variables should have been saved by now.
-	       string__append("Copy ", Description, Comment),
-               CopyCode = node([
-                       assign(reg(r, 1), VarRVal) - Comment
-               ])
-	},
-	{ Code = tree(VarCode, CopyCode) }.
+	]) }.
+call_gen__generic_call_nonvar_setup(aditi_builtin(Builtin, _),
+		InVars, OutVars, Code) -->
+	call_gen__aditi_builtin_setup(Builtin, InVars, OutVars, Code).
 
-:- pred call_gen__aditi_builtin_setup(aditi_builtin,
-	list(prog_var), list(prog_var), code_tree, code_info, code_info).
-:- mode call_gen__aditi_builtin_setup(in, in, in, out, in, out) is det.
+:- pred call_gen__aditi_builtin_setup(aditi_builtin::in,
+	list(prog_var)::in, list(prog_var)::in, code_tree::out,
+	code_info::in, code_info::out) is det.
 
 call_gen__aditi_builtin_setup(
 		aditi_call(PredProcId, NumInputs, InputTypes, NumOutputs),
@@ -391,6 +379,7 @@
 	{ rl__get_entry_proc_name(ModuleInfo, PredProcId, ProcName) },
 	{ rl__proc_name_to_string(ProcName, ProcStr) },
 	{ rl__schema_to_string(ModuleInfo, InputTypes, InputSchema) },
+	code_info__clobber_regs([reg(r, 1), reg(r, 2), reg(r, 3), reg(r, 4)]),
 	{ SetupCode = node([
 		assign(reg(r, 1), const(string_const(ProcStr))) -
 			"Assign name of procedure to call",
@@ -405,6 +394,7 @@
 call_gen__aditi_builtin_setup(
 		aditi_tuple_insert_delete(InsertOrDelete, PredId),
 		InputArgs, _, SetupCode) -->
+	code_info__clobber_regs([reg(r, 1), reg(r, 2), reg(r, 3), reg(r, 4)]),
 	call_gen__setup_base_relation_name(PredId, NameCode),
 
 	code_info__get_module_info(ModuleInfo),
@@ -472,30 +462,31 @@
 	call_gen__aditi_insert_delete_modify_setup(InsertDelMod,
 		PredId, SetupCode).
 
-:- pred call_gen__aditi_insert_delete_modify_setup(aditi_insert_delete_modify,
-		pred_id, code_tree, code_info, code_info).
-:- mode call_gen__aditi_insert_delete_modify_setup(in, in, out,
-		in, out) is det.
+:- pred call_gen__aditi_insert_delete_modify_setup(
+	aditi_insert_delete_modify::in, pred_id::in, code_tree::out,
+	code_info::in, code_info::out) is det.
 
 call_gen__aditi_insert_delete_modify_setup(bulk_insert, PredId, SetupCode) -->
+	code_info__clobber_regs([reg(r, 1), reg(r, 2)]),
 	call_gen__setup_base_relation_name(PredId, RelNameCode),
 	call_gen__setup_update_proc_name(rl__get_insert_proc_name,
 		PredId, reg(r, 2), ProcNameCode),
 	{ SetupCode = tree(RelNameCode, ProcNameCode) }.
 call_gen__aditi_insert_delete_modify_setup(delete(_), PredId, SetupCode) -->
+	code_info__clobber_regs([reg(r, 1), reg(r, 2)]),
 	call_gen__setup_base_relation_name(PredId, RelNameCode),
 	call_gen__setup_update_proc_name(rl__get_delete_proc_name,
 		PredId, reg(r, 2), ProcNameCode),
 	{ SetupCode = tree(RelNameCode, ProcNameCode) }.
 call_gen__aditi_insert_delete_modify_setup(modify(_), PredId, SetupCode) -->
+	code_info__clobber_regs([reg(r, 1), reg(r, 2)]),
 	call_gen__setup_base_relation_name(PredId, RelNameCode),
 	call_gen__setup_update_proc_name(rl__get_modify_proc_name,
 		PredId, reg(r, 2), ProcNameCode),
 	{ SetupCode = tree(RelNameCode, ProcNameCode) }.
 
-:- pred call_gen__setup_base_relation_name(pred_id,
-		code_tree, code_info, code_info).
-:- mode call_gen__setup_base_relation_name(in, out, in, out) is det.
+:- pred call_gen__setup_base_relation_name(pred_id::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
 call_gen__setup_base_relation_name(PredId, SetupCode) -->
 	code_info__get_module_info(ModuleInfo),
@@ -525,9 +516,8 @@
 
 %---------------------------------------------------------------------------%
 
-:- pred call_gen__prepare_for_call(code_model, code_tree, call_model,
-	code_info, code_info).
-:- mode call_gen__prepare_for_call(in, out, out, in, out) is det.
+:- pred call_gen__prepare_for_call(code_model::in, code_tree::out,
+	call_model::out, code_info::in, code_info::out) is det.
 
 call_gen__prepare_for_call(CodeModel, FlushCode, CallModel) -->
 	code_info__succip_is_used,
@@ -547,8 +537,8 @@
 		code_info__set_resume_point_and_frame_to_unknown
 	).
 
-:- pred call_gen__handle_failure(code_model, code_tree, code_info, code_info).
-:- mode call_gen__handle_failure(in, out, in, out ) is det.
+:- pred call_gen__handle_failure(code_model::in, code_tree::out,
+	code_info::in, code_info::out) is det.
 
 call_gen__handle_failure(CodeModel, FailHandlingCode) -->
 	( { CodeModel = model_semi } ->
@@ -571,8 +561,7 @@
 		{ FailHandlingCode = empty }
 	).
 
-:- pred call_gen__call_comment(code_model, string).
-:- mode call_gen__call_comment(in, out) is det.
+:- pred call_gen__call_comment(code_model::in, string::out) is det.
 
 call_gen__call_comment(model_det,  "branch to det procedure").
 call_gen__call_comment(model_semi, "branch to semidet procedure").
@@ -580,59 +569,61 @@
 
 %---------------------------------------------------------------------------%
 
-call_gen__save_variables(OutArgs, Code) -->
-	code_info__get_known_variables(Variables0),
-	{ set__list_to_set(Variables0, Vars0) },
-	code_info__get_module_info(ModuleInfo),
-	code_info__get_pred_id(PredId),
-	{ module_info_pred_info(ModuleInfo, PredId, PredInfo) },
-	code_info__get_globals(Globals),
-	{ body_should_use_typeinfo_liveness(PredInfo, Globals,
-		TypeInfoLiveness) },
-	code_info__get_proc_info(ProcInfo),
-	{ proc_info_vartypes(ProcInfo, VarTypes) },
-	{ proc_info_typeinfo_varmap(ProcInfo, TVarMap) },
-	{ proc_info_maybe_complete_with_typeinfo_vars(Vars0, TypeInfoLiveness,
-		VarTypes, TVarMap, Vars1) },
-	{ set__difference(Vars1, OutArgs, Vars) },
-	{ set__to_sorted_list(Vars, Variables) },
-	call_gen__save_variables_2(Variables, Code).
-
-:- pred call_gen__save_variables_2(list(prog_var), code_tree,
-		code_info, code_info).
-:- mode call_gen__save_variables_2(in, out, in, out) is det.
-
-call_gen__save_variables_2([], empty) --> [].
-call_gen__save_variables_2([Var | Vars], Code) -->
-	code_info__save_variable_on_stack(Var, CodeA),
-	call_gen__save_variables_2(Vars, CodeB),
-	{ Code = tree(CodeA, CodeB) }.
+	% We must update the code generator state to reflect
+	% the situation after the call before building
+	% the return liveness info.
+	%
+	% It is possible for some output arguments to be local
+	% to this goal, i.e. for it not to appear in later code.
+	% In such cases, we consider them to be live at the point
+	% of the return, so that if debugging is enabled, their
+	% values can be inspected (or if they are typeinfos, their
+	% values can be used to inspect other variables), but then
+	% kill them so that they are not live beyond this goal.
+	%
+	% ArgsInfos should list all the output arguments of the call.
+	% (It may contain the input arguments as well; handle_return
+	% ignores them.)
 
-%---------------------------------------------------------------------------%
+:- pred call_gen__handle_return(assoc_list(prog_var, arg_info)::in,
+	instmap::in, list(liveinfo)::out,
+	code_info::in, code_info::out) is det.
 
-:- pred call_gen__rebuild_registers(assoc_list(prog_var, arg_info),
-							code_info, code_info).
-:- mode call_gen__rebuild_registers(in, in, out) is det.
+call_gen__handle_return(ArgsInfos, ReturnInstMap, ReturnLiveLvalues) -->
+	call_gen__rebuild_registers(ArgsInfos, KillSet),
+	{ call_gen__output_arg_locs(ArgsInfos, OutputArgLocs) },
+	code_info__generate_return_live_lvalues(OutputArgLocs, ReturnInstMap,
+		ReturnLiveLvalues),
+	code_info__make_vars_forward_dead(KillSet).
 
-call_gen__rebuild_registers(Args) -->
+:- pred call_gen__rebuild_registers(assoc_list(prog_var, arg_info)::in,
+	set(prog_var)::out, code_info::in, code_info::out) is det.
+
+call_gen__rebuild_registers(Args, KillSet) -->
 	code_info__clear_all_registers,
-	call_gen__rebuild_registers_2(Args).
+	code_info__get_forward_live_vars(Liveness),
+	{ set__init(KillSet0) },
+	call_gen__rebuild_registers_2(Args, Liveness, KillSet0, KillSet).
 
-:- pred call_gen__rebuild_registers_2(assoc_list(prog_var, arg_info),
-							code_info, code_info).
-:- mode call_gen__rebuild_registers_2(in, in, out) is det.
+:- pred call_gen__rebuild_registers_2(assoc_list(prog_var, arg_info)::in,
+	set(prog_var)::in, set(prog_var)::in, set(prog_var)::out,
+	code_info::in, code_info::out) is det.
 
-call_gen__rebuild_registers_2([]) --> [].
-call_gen__rebuild_registers_2([Var - arg_info(ArgLoc, Mode) | Args]) -->
-	(
-		{ Mode = top_out }
-	->
+call_gen__rebuild_registers_2([], _, KillSet, KillSet) --> [].
+call_gen__rebuild_registers_2([Var - arg_info(ArgLoc, Mode) | Args], Liveness,
+		KillSet0, KillSet) -->
+	( { Mode = top_out } ->
 		{ code_util__arg_loc_to_register(ArgLoc, Register) },
-		code_info__set_var_location(Var, Register)
+		code_info__set_var_location(Var, Register),
+		{ set__member(Var, Liveness) ->
+			KillSet1 = KillSet0
+		;
+			set__insert(KillSet0, Var, KillSet1)
+		}
 	;
-		{ true }
+		{ KillSet1 = KillSet0 }
 	),
-	call_gen__rebuild_registers_2(Args).
+	call_gen__rebuild_registers_2(Args, Liveness, KillSet1, KillSet).
 
 %---------------------------------------------------------------------------%
 
@@ -653,9 +644,12 @@
 		(
 			{ SimpleCode = assign(Var, AssignExpr) }
 		->
+			( code_info__variable_is_forward_live(Var) ->
 			{ Rval = convert_simple_expr(AssignExpr) },
-			code_info__cache_expression(Var, Rval),
+				code_info__assign_expr_to_var(Var, Rval, Code)
+			;
 			{ Code = empty }
+			)
 		;
 			{ error("Malformed det builtin predicate") }
 		)
@@ -677,6 +671,7 @@
 	).
 
 :- func convert_simple_expr(simple_expr(prog_var)) = rval.
+
 convert_simple_expr(leaf(Var)) = var(Var).
 convert_simple_expr(int_const(Int)) = const(int_const(Int)).
 convert_simple_expr(float_const(Float)) = const(float_const(Float)).
@@ -685,10 +680,10 @@
 convert_simple_expr(binary(BinOp, Expr1, Expr2)) =
 	binop(BinOp, convert_simple_expr(Expr1), convert_simple_expr(Expr2)).
 
-:- pred call_gen__generate_simple_test(simple_expr(prog_var), rval,
-		code_tree, code_info, code_info).
-:- mode call_gen__generate_simple_test(in(simple_test_expr), out, out, in, out)
-		is det.
+:- pred call_gen__generate_simple_test(
+	simple_expr(prog_var)::in(simple_test_expr), rval::out,
+	code_tree::out, code_info::in, code_info::out) is det.
+
 call_gen__generate_simple_test(TestExpr, Rval, ArgCode) -->
 	(
 		{ TestExpr = binary(BinOp, X0, Y0) },
@@ -705,9 +700,8 @@
 		{ Rval = unop(UnOp, X) }
 	).
 
-:- pred call_gen__generate_builtin_arg(rval, rval, code_tree,
-	code_info, code_info).
-:- mode call_gen__generate_builtin_arg(in, out, out, in, out) is det.
+:- pred call_gen__generate_builtin_arg(rval::in, rval::out, code_tree::out,
+	code_info::in, code_info::out) is det.
 
 call_gen__generate_builtin_arg(Rval0, Rval, Code) -->
 	( { Rval0 = var(Var) } ->
@@ -721,7 +715,7 @@
 %---------------------------------------------------------------------------%
 
 call_gen__partition_args([], [], []).
-call_gen__partition_args([V - arg_info(_Loc,Mode) | Rest], Ins, Outs) :-
+call_gen__partition_args([V - arg_info(_Loc, Mode) | Rest], Ins, Outs) :-
 	(
 		Mode = top_in
 	->
@@ -734,17 +728,14 @@
 
 %---------------------------------------------------------------------------%
 
-:- pred call_gen__select_out_args(assoc_list(prog_var, arg_info),
-		set(prog_var)).
-:- mode call_gen__select_out_args(in, out) is det.
+:- pred call_gen__select_out_args(assoc_list(prog_var, arg_info)::in,
+	set(prog_var)::out) is det.
 
 call_gen__select_out_args([], Out) :-
 	set__init(Out).
 call_gen__select_out_args([V - arg_info(_Loc, Mode) | Rest], Out) :-
 	call_gen__select_out_args(Rest, Out0),
-	(
-		Mode = top_out
-	->
+	( Mode = top_out ->
 		set__insert(Out0, V, Out)
 	;
 		Out = Out0
@@ -752,43 +743,36 @@
 
 %---------------------------------------------------------------------------%
 
-:- pred call_gen__input_args(list(arg_info), list(arg_loc)).
-:- mode call_gen__input_args(in, out) is det.
+:- pred call_gen__input_args(list(arg_info)::in, list(arg_loc)::out) is det.
 
 call_gen__input_args([], []).
 call_gen__input_args([arg_info(Loc, Mode) | Args], Vs) :-
-	(
-		Mode = top_in
-	->
-		Vs = [Loc |Vs0]
+	call_gen__input_args(Args, Vs0),
+	( Mode = top_in ->
+		Vs = [Loc | Vs0]
 	;
 		Vs = Vs0
-	),
-	call_gen__input_args(Args, Vs0).
+	).
 
 %---------------------------------------------------------------------------%
 
 call_gen__input_arg_locs([], []).
 call_gen__input_arg_locs([Var - arg_info(Loc, Mode) | Args], Vs) :-
-	(
-		Mode = top_in
-	->
+	call_gen__input_arg_locs(Args, Vs0),
+	( Mode = top_in ->
 		Vs = [Var - Loc | Vs0]
 	;
 		Vs = Vs0
-	),
-	call_gen__input_arg_locs(Args, Vs0).
+	).
 
 call_gen__output_arg_locs([], []).
 call_gen__output_arg_locs([Var - arg_info(Loc, Mode) | Args], Vs) :-
-	(
-		Mode = top_out
-	->
+	call_gen__output_arg_locs(Args, Vs0),
+	( Mode = top_out ->
 		Vs = [Var - Loc | Vs0]
 	;
 		Vs = Vs0
-	),
-	call_gen__output_arg_locs(Args, Vs0).
+	).
 
 %---------------------------------------------------------------------------%
 
@@ -804,30 +788,27 @@
 	]) }.
 
 %---------------------------------------------------------------------------%
+
+:- pred call_gen__give_vars_consecutive_regs(list(prog_var)::in, int::in,	
+	list(lval)::out) is det.
 
-:- pred call_gen__generate_immediate_args(list(prog_var), int, list(lval),
-		code_tree, code_info, code_info).
-:- mode call_gen__generate_immediate_args(in, in, out, out, in, out) is det.
-
-call_gen__generate_immediate_args([], _N, [], empty) --> [].
-call_gen__generate_immediate_args([V | Vs], N0, [Lval | Lvals], Code) -->
-	{ Lval = reg(r, N0) },
-	code_info__place_var(V, Lval, Code0),
-	{ N1 is N0 + 1 },
-	call_gen__generate_immediate_args(Vs, N1, Lvals, Code1),
-	{ Code = tree(Code0, Code1) }.
+call_gen__give_vars_consecutive_regs([], _N, []).
+call_gen__give_vars_consecutive_regs([_Var | Vars], N0, [Lval | Lvals]) :-
+	Lval = reg(r, N0),
+	N1 is N0 + 1,
+	call_gen__give_vars_consecutive_regs(Vars, N1, Lvals).
 
 %---------------------------------------------------------------------------%
+
+:- pred call_gen__give_vars_consecutive_arg_infos(list(prog_var)::in, int::in,
+	arg_mode::in, assoc_list(prog_var, arg_info)::out) is det.
 
-:- pred call_gen__outvars_to_outargs(list(prog_var), int,
-		assoc_list(prog_var, arg_info)).
-:- mode call_gen__outvars_to_outargs(in, in, out) is det.
-
-call_gen__outvars_to_outargs([], _N, []).
-call_gen__outvars_to_outargs([V | Vs], N0, [V - Arg | ArgInfos]) :-
-	Arg = arg_info(N0, top_out),
+call_gen__give_vars_consecutive_arg_infos([], _N, _M, []).
+call_gen__give_vars_consecutive_arg_infos([Var | Vars], N0, ArgMode,
+		[Var - ArgInfo | ArgInfos]) :-
+	ArgInfo = arg_info(N0, ArgMode),
 	N1 is N0 + 1,
-	call_gen__outvars_to_outargs(Vs, N1, ArgInfos).
+	call_gen__give_vars_consecutive_arg_infos(Vars, N1, ArgMode, ArgInfos).
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
Index: compiler/code_exprn.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_exprn.m,v
retrieving revision 1.61
diff -u -b -r1.61 code_exprn.m
--- compiler/code_exprn.m	2000/01/14 01:10:12	1.61
+++ compiler/code_exprn.m	2000/07/17 06:04:49
@@ -138,21 +138,21 @@
 		exprn_info, exprn_info).
 :- mode code_exprn__produce_var(in, out, out, in, out) is det.
 
-%	code_exprn__produce_var_in_reg(Var, Rval, Code, ExprnInfo0, ExprnInfo)
+%	code_exprn__produce_var_in_reg(Var, Lval, Code, ExprnInfo0, ExprnInfo)
 %		Produces a code fragment Code to evaluate Var and
-%		provide it as an Rval of the form lval(reg(_)).
+%		provide it as an Lval of the form reg(_).
 
-:- pred code_exprn__produce_var_in_reg(prog_var, rval, code_tree,
+:- pred code_exprn__produce_var_in_reg(prog_var, lval, code_tree,
 	exprn_info, exprn_info).
 :- mode code_exprn__produce_var_in_reg(in, out, out, in, out) is det.
 
-%	code_exprn__produce_var_in_reg_or_stack(Var, FollowVars, Rval, Code,
+%	code_exprn__produce_var_in_reg_or_stack(Var, FollowVars, Lval, Code,
 %			ExprnInfo0, ExprnInfo)
 %		Produces a code fragment Code to evaluate Var and
-%		provide it as an Rval of the form lval(reg(_)),
-%		lval(stackvar(_)), or lval(framevar(_)).
+%		provide it as an Lval of the form reg(_), stackvar(_),
+%		or framevar(_).
 
-:- pred code_exprn__produce_var_in_reg_or_stack(prog_var, rval, code_tree,
+:- pred code_exprn__produce_var_in_reg_or_stack(prog_var, lval, code_tree,
 	exprn_info, exprn_info).
 :- mode code_exprn__produce_var_in_reg_or_stack(in, out, out, in, out) is det.
 
@@ -1414,59 +1414,63 @@
 
 %------------------------------------------------------------------------------%
 
-code_exprn__produce_var_in_reg(Var, Rval, Code) -->
+code_exprn__produce_var_in_reg(Var, Lval, Code) -->
 	code_exprn__get_var_status(Var, Stat),
 	(
 		{ Stat = evaled(Rvals) },
 		{ set__to_sorted_list(Rvals, RvalList) },
-		{ code_exprn__select_reg_rval(RvalList, Rval0) }
+		{ code_exprn__select_reg_rval(RvalList, Lval0) }
 	->
 		{ Code = empty },
-		{ Rval = Rval0 }
+		{ Lval = Lval0 }
 	;
 		code_exprn__select_preferred_reg(Var, Lval),
-		code_exprn__place_var(Var, Lval, Code),
-		{ Rval = lval(Lval) }
+		code_exprn__place_var(Var, Lval, Code)
 	).
 
-code_exprn__produce_var_in_reg_or_stack(Var, Rval, Code) -->
+code_exprn__produce_var_in_reg_or_stack(Var, Lval, Code) -->
 	code_exprn__get_var_status(Var, Stat),
 	(
 		{ Stat = evaled(Rvals) },
 		{ set__to_sorted_list(Rvals, RvalList) },
-		{ code_exprn__select_reg_or_stack_rval(RvalList, Rval0) }
+		{ code_exprn__select_reg_or_stack_rval(RvalList, Lval0) }
 	->
 		{ Code = empty },
-		{ Rval = Rval0 }
+		{ Lval = Lval0 }
 	;
 		code_exprn__select_preferred_lval(Var, Lval),
-		code_exprn__place_var(Var, Lval, Code),
-		{ Rval = lval(Lval) }
+		code_exprn__place_var(Var, Lval, Code)
 	).
 
 %------------------------------------------------------------------------------%
 
-:- pred code_exprn__select_reg_rval(list(rval), rval).
+:- pred code_exprn__select_reg_rval(list(rval), lval).
 :- mode code_exprn__select_reg_rval(in, out) is semidet.
 
-code_exprn__select_reg_rval([Rval0 | Rvals0], Rval) :-
-	( Rval0 = lval(reg(_, _)) ->
-		Rval = Rval0
+code_exprn__select_reg_rval([Rval0 | Rvals0], Lval) :-
+	(
+		Rval0 = lval(Lval0),
+		Lval0 = reg(_, _)
+	->
+		Lval = Lval0
 	;
-		code_exprn__select_reg_rval(Rvals0, Rval)
+		code_exprn__select_reg_rval(Rvals0, Lval)
 	).
 
-:- pred code_exprn__select_reg_or_stack_rval(list(rval), rval).
+:- pred code_exprn__select_reg_or_stack_rval(list(rval), lval).
 :- mode code_exprn__select_reg_or_stack_rval(in, out) is semidet.
 
-code_exprn__select_reg_or_stack_rval([Rval0 | Rvals0], Rval) :-
+code_exprn__select_reg_or_stack_rval([Rval0 | Rvals0], Lval) :-
 	(
-		Rval0 = lval(Lval),
-		( Lval = reg(_, _) ; Lval = stackvar(_) ; Lval = framevar(_) )
+		Rval0 = lval(Lval0),
+		( Lval0 = reg(_, _)
+		; Lval0 = stackvar(_)
+		; Lval0 = framevar(_)
+		)
 	->
-		Rval = Rval0
+		Lval = Lval0
 	;
-		code_exprn__select_reg_or_stack_rval(Rvals0, Rval)
+		code_exprn__select_reg_or_stack_rval(Rvals0, Lval)
 	).
 
 %------------------------------------------------------------------------------%
@@ -1477,8 +1481,9 @@
 
 code_exprn__select_preferred_lval(Var, Lval) -->
 	code_exprn__get_follow_vars(FollowVars),
+	{ FollowVars = follow_vars(FollowVarsMap, NextNonReserved) },
 	(
-		{ map__search(FollowVars, Var, PrefLval) }
+		{ map__search(FollowVarsMap, Var, PrefLval) }
 	->
 		(
 			\+ { unreal_lval(PrefLval) },
@@ -1486,10 +1491,11 @@
 		->
 			{ Lval = PrefLval }
 		;
-			code_exprn__get_spare_reg(r, Lval)
+			code_exprn__get_spare_reg_start_from(r,
+				NextNonReserved, Lval)
 		)
 	;
-		code_exprn__get_spare_reg(r, Lval)
+		code_exprn__get_spare_reg_start_from(r, NextNonReserved, Lval)
 	).
 
 :- pred code_exprn__select_preferred_reg(prog_var, lval,
@@ -1498,8 +1504,9 @@
 
 code_exprn__select_preferred_reg(Var, Lval) -->
 	code_exprn__get_follow_vars(FollowVars),
+	{ FollowVars = follow_vars(FollowVarsMap, NextNonReserved) },
 	(
-		{ map__search(FollowVars, Var, PrefLval) },
+		{ map__search(FollowVarsMap, Var, PrefLval) },
 		{ PrefLval = reg(_, _) }
 	->
 		(
@@ -1508,10 +1515,11 @@
 		->
 			{ Lval = PrefLval }
 		;
-			code_exprn__get_spare_reg(r, Lval)
+			code_exprn__get_spare_reg_start_from(r,
+				NextNonReserved, Lval)
 		)
 	;
-		code_exprn__get_spare_reg(r, Lval)
+		code_exprn__get_spare_reg_start_from(r, NextNonReserved, Lval)
 	).
 
 :- pred unreal_lval(lval).
@@ -1702,6 +1710,14 @@
 %------------------------------------------------------------------------------%
 
 	% Warning: if you get a reg, you must mark it as in use yourself.
+
+:- pred code_exprn__get_spare_reg_start_from(reg_type, int, lval,
+	exprn_info, exprn_info).
+:- mode code_exprn__get_spare_reg_start_from(in, in, out, in, out) is det.
+
+code_exprn__get_spare_reg_start_from(RegType, N, Lval) -->
+	code_exprn__get_regs(Regs),
+	{ code_exprn__get_spare_reg_2(RegType, N, Regs, Lval) }.
 
 :- pred code_exprn__get_spare_reg(reg_type, lval, exprn_info, exprn_info).
 :- mode code_exprn__get_spare_reg(in, out, in, out) is det.
Index: compiler/code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_gen.m,v
retrieving revision 1.79
diff -u -b -r1.79 code_gen.m
--- compiler/code_gen.m	2000/08/11 08:18:54	1.79
+++ compiler/code_gen.m	2000/08/23 03:26:56
@@ -31,7 +31,6 @@
 :- interface.
 
 :- import_module hlds_module, hlds_pred, hlds_goal, llds, code_info.
-:- import_module globals.
 :- import_module list, io, counter.
 
 		% Translate a HLDS module to LLDS.
@@ -46,7 +45,7 @@
 		% of cell numbers.
 
 :- pred generate_proc_code(pred_info::in, proc_info::in,
-	proc_id::in, pred_id::in, module_info::in, globals::in,
+	proc_id::in, pred_id::in, module_info::in,
 	global_data::in, global_data::out, counter::in, counter::out,
 	c_procedure::out) is det.
 
@@ -65,7 +64,7 @@
 :- import_module continuation_info, trace, options, hlds_out.
 :- import_module code_aux, middle_rec, passes_aux, llds_out.
 :- import_module code_util, type_util, mode_util, goal_util.
-:- import_module prog_data, prog_out, instmap.
+:- import_module prog_data, prog_out, prog_util, instmap, globals.
 :- import_module bool, char, int, string.
 :- import_module map, assoc_list, set, term, tree, std_util, require, varset.
 
@@ -86,10 +85,26 @@
 	list(pred_id)::in, list(c_procedure)::out,
 	io__state::di, io__state::uo) is det.
 
+:- pred generate_maybe_pred_code(module_info::in, module_info::out,
+	global_data::in, global_data::out, pred_id::in, list(c_procedure)::out,
+	io__state::di, io__state::uo) is det.
+
 generate_pred_list_code(ModuleInfo, ModuleInfo, GlobalData, GlobalData,
 		[], []) --> [].
 generate_pred_list_code(ModuleInfo0, ModuleInfo, GlobalData0, GlobalData,
 		[PredId | PredIds], Predicates) -->
+	generate_maybe_pred_code(ModuleInfo0, ModuleInfo1,
+		GlobalData0, GlobalData1, PredId, Predicates0),
+	generate_pred_list_code(ModuleInfo1, ModuleInfo,
+		GlobalData1, GlobalData, PredIds, Predicates1),
+	{ list__append(Predicates0, Predicates1, Predicates) }.
+
+	% Note that some of the logic of generate_maybe_pred_code is duplicated
+	% by mercury_compile__backend_pass_by_preds, so modifications here may
+	% also need to be repeated there.
+
+generate_maybe_pred_code(ModuleInfo0, ModuleInfo, GlobalData0, GlobalData,
+		PredId, Predicates) -->
 	{ module_info_preds(ModuleInfo0, PredInfos) },
 		% get the pred_info structure for this predicate
 	{ map__lookup(PredInfos, PredId, PredInfo) },
@@ -101,65 +116,86 @@
 		; hlds_pred__pred_info_is_aditi_relation(PredInfo)
 		}
 	->
-		{ Predicates0 = [] },
-		{ ModuleInfo1 = ModuleInfo0 },
-		{ GlobalData1 = GlobalData0 }
+		{ Predicates = [] },
+		{ ModuleInfo = ModuleInfo0 },
+		{ GlobalData = GlobalData0 }
 	;
-		generate_pred_code(ModuleInfo0, ModuleInfo1,
-				GlobalData0, GlobalData1,
-				PredId, PredInfo, ProcIds, Predicates0)
-	),
-	{ list__append(Predicates0, Predicates1, Predicates) },
-		% and generate the code for the rest of the predicates
-	generate_pred_list_code(ModuleInfo1, ModuleInfo,
-		GlobalData1, GlobalData, PredIds, Predicates1).
-
-	% Translate a HLDS predicate to LLDS.
-
-:- pred generate_pred_code(module_info::in, module_info::out,
-	global_data::in, global_data::out,
-	pred_id::in, pred_info::in, list(proc_id)::in, list(c_procedure)::out,
-	io__state::di, io__state::uo) is det.
-
-generate_pred_code(ModuleInfo0, ModuleInfo, GlobalData0, GlobalData,
-		PredId, PredInfo, ProcIds, Code) -->
-	globals__io_lookup_bool_option(very_verbose, VeryVerbose),
+		{ module_info_globals(ModuleInfo0, Globals0) },
+		{ globals__lookup_bool_option(Globals0, very_verbose,
+			VeryVerbose) },
 	( { VeryVerbose = yes } ->
 		io__write_string("% Generating code for "),
 		hlds_out__write_pred_id(ModuleInfo0, PredId),
 		io__write_string("\n"),
-		globals__io_lookup_bool_option(statistics, Statistics),
+			{ globals__lookup_bool_option(Globals0,
+				statistics, Statistics) },
 		maybe_report_stats(Statistics)
 	;
 		[]
 	),
-	{ module_info_get_cell_counter(ModuleInfo0, CellCounter0) },
-	globals__io_get_globals(Globals),
-	{ generate_proc_list_code(ProcIds, PredId, PredInfo, ModuleInfo0,
-		Globals, GlobalData0, GlobalData, CellCounter0, CellCounter,
-		[], Code) },
-	{ module_info_set_cell_counter(ModuleInfo0, CellCounter, ModuleInfo) }.
+		{
+			pred_info_module(PredInfo, PredModule),
+			pred_info_name(PredInfo, PredName),
+			pred_info_arity(PredInfo, PredArity),
+			no_type_info_builtin(PredModule, PredName, PredArity)
+		->
+				% These predicates should never be traced,
+				% since they do not obey typeinfo_liveness.
+				% Since they may be opt_imported into other
+				% modules, we must switch off the tracing
+				% of such preds on a pred-by-pred basis.
+			globals__get_trace_level(Globals0, TraceLevel),
+			globals__set_trace_level(Globals0, none, Globals1),
+			module_info_set_globals(ModuleInfo0, Globals1,
+				ModuleInfo1),
+			generate_pred_code(ModuleInfo1, ModuleInfo2,
+				GlobalData0, GlobalData,
+				PredId, PredInfo, ProcIds, Predicates),
+			module_info_globals(ModuleInfo2, Globals2),
+			globals__set_trace_level(Globals2, TraceLevel,
+				Globals),
+			module_info_set_globals(ModuleInfo2, Globals,
+				ModuleInfo)
+		;
+			generate_pred_code(ModuleInfo0, ModuleInfo,
+				GlobalData0, GlobalData,
+				PredId, PredInfo, ProcIds, Predicates)
+		}
+	).
+
+	% Translate a HLDS predicate to LLDS.
+
+:- pred generate_pred_code(module_info::in, module_info::out,
+	global_data::in, global_data::out, pred_id::in, pred_info::in,
+	list(proc_id)::in, list(c_procedure)::out) is det.
+
+generate_pred_code(ModuleInfo0, ModuleInfo, GlobalData0, GlobalData,
+		PredId, PredInfo, ProcIds, Code) :-
+	module_info_get_cell_counter(ModuleInfo0, CellCounter0),
+	generate_proc_list_code(ProcIds, PredId, PredInfo, ModuleInfo0,
+		GlobalData0, GlobalData, CellCounter0, CellCounter,
+		[], Code),
+	module_info_set_cell_counter(ModuleInfo0, CellCounter, ModuleInfo).
 
 	% Translate all the procedures of a HLDS predicate to LLDS.
 
 :- pred generate_proc_list_code(list(proc_id)::in, pred_id::in, pred_info::in,
-	module_info::in, globals::in, global_data::in, global_data::out,
+	module_info::in, global_data::in, global_data::out,
 	counter::in, counter::out,
 	list(c_procedure)::in, list(c_procedure)::out) is det.
 
-generate_proc_list_code([], _PredId, _PredInfo, _ModuleInfo, _Globals,
+generate_proc_list_code([], _PredId, _PredInfo, _ModuleInfo,
 		GlobalData, GlobalData, CellCounter, CellCounter,
 		Procs, Procs).
 generate_proc_list_code([ProcId | ProcIds], PredId, PredInfo, ModuleInfo0,
-		Globals, GlobalData0, GlobalData, CellCounter0, CellCounter,
+		GlobalData0, GlobalData, CellCounter0, CellCounter,
 		Procs0, Procs) :-
 	pred_info_procedures(PredInfo, ProcInfos),
 	map__lookup(ProcInfos, ProcId, ProcInfo),
 	generate_proc_code(PredInfo, ProcInfo, ProcId, PredId, ModuleInfo0,
-		Globals, GlobalData0, GlobalData1, CellCounter0, CellCounter1,
-		Proc),
+		GlobalData0, GlobalData1, CellCounter0, CellCounter1, Proc),
 	generate_proc_list_code(ProcIds, PredId, PredInfo, ModuleInfo0,
-		Globals, GlobalData1, GlobalData, CellCounter1, CellCounter,
+		GlobalData1, GlobalData, CellCounter1, CellCounter,
 		[Proc | Procs0], Procs).
 
 %---------------------------------------------------------------------------%
@@ -181,7 +217,7 @@
 
 %---------------------------------------------------------------------------%
 
-generate_proc_code(PredInfo, ProcInfo, ProcId, PredId, ModuleInfo, Globals,
+generate_proc_code(PredInfo, ProcInfo, ProcId, PredId, ModuleInfo,
 		GlobalData0, GlobalData, CellCounter0, CellCounter, Proc) :-
 	proc_info_interface_determinism(ProcInfo, Detism),
 	proc_info_interface_code_model(ProcInfo, CodeModel),
@@ -192,8 +228,10 @@
 		MaybeFollowVars = yes(FollowVars)
 	;
 		MaybeFollowVars = no,
-		map__init(FollowVars)
+		map__init(FollowVarsMap),
+		FollowVars = follow_vars(FollowVarsMap, 1)
 	),
+	module_info_globals(ModuleInfo, Globals),
 	continuation_info__basic_stack_layout_for_proc(PredInfo, Globals,
 	BasicStackLayout, ForceProcId),
 	( BasicStackLayout = yes ->
Index: compiler/code_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_info.m,v
retrieving revision 1.250
diff -u -b -r1.250 code_info.m
--- compiler/code_info.m	2000/08/11 08:18:56	1.250
+++ compiler/code_info.m	2000/08/11 08:25:28
@@ -36,8 +36,8 @@
 
 :- implementation.
 
-:- import_module code_util, code_exprn, llds_out, prog_out.
-:- import_module arg_info, type_util, mode_util, options.
+:- import_module code_util, code_exprn, var_locn, llds_out, prog_out.
+:- import_module exprn_aux, arg_info, type_util, mode_util, options.
 
 :- import_module term, varset.
 :- import_module set, stack.
@@ -165,10 +165,10 @@
 :- pred code_info__set_zombies(set(prog_var)::in,
 	code_info::in, code_info::out) is det.
 
-:- pred code_info__get_exprn_info(exprn_info::out,
+:- pred code_info__get_var_locns_info(var_locns_info::out,
 	code_info::in, code_info::out) is det.
 
-:- pred code_info__set_exprn_info(exprn_info::in,
+:- pred code_info__set_var_locns_info(var_locns_info::in,
 	code_info::in, code_info::out) is det.
 
 :- pred code_info__get_temps_in_use(set(lval)::out,
@@ -261,7 +261,7 @@
 				% Zombie variables; variables that are not
 				% forward live but which are protected by
 				% an enclosing resume point.
-		exprn_info :: exprn_info,
+		var_locns_info :: var_locns_info,
 				% A map storing the information about
 				% the status of each known variable.
 				% (Known vars = forward live vars + zombies)
@@ -318,6 +318,10 @@
 				% enabled.
 	).
 
+:- type var_locns_info
+	--->	exprn_info(exprn_info)
+	;	var_locn_info(var_locn_info).
+
 %---------------------------------------------------------------------------%
 
 code_info__init(SaveSuccip, Globals, PredId, ProcId, ProcInfo, FollowVars,
@@ -330,11 +334,32 @@
 	proc_info_interface_code_model(ProcInfo, CodeModel),
 	assoc_list__from_corresponding_lists(HeadVars, ArgInfos, Args),
 	arg_info__build_input_arg_list(Args, ArgList),
-	globals__get_options(Globals, Options),
 	proc_info_varset(ProcInfo, VarSet),
 	proc_info_stack_slots(ProcInfo, StackSlots),
-	code_exprn__init_state(ArgList, VarSet, StackSlots, FollowVars,
-		Options, ExprnInfo),
+	globals__lookup_bool_option(Globals, lazy_code, LazyCode),
+	globals__get_options(Globals, Options),
+	globals__get_trace_level(Globals, TraceLevel),
+	( TraceLevel \= none ->
+		trace__fail_vars(ModuleInfo, ProcInfo, FailVars),
+		MaybeFailVars = yes(FailVars),
+		set__union(Liveness, FailVars, EffLiveness)
+	;
+		MaybeFailVars = no,
+		EffLiveness = Liveness
+	),
+	(
+		LazyCode = yes,
+		ArgRvalList = assoc_list__map_values(
+			exprn_aux__var_lval_to_rval, ArgList),
+		code_exprn__init_state(ArgRvalList, VarSet, StackSlots,
+			FollowVars, Options, ExprnInfo),
+		VarLocnsInfo = exprn_info(ExprnInfo)
+	;
+		LazyCode = no,
+		var_locn__init_state(ArgList, EffLiveness, VarSet,
+			StackSlots, FollowVars, Options, VarLocnInfo),
+		VarLocnsInfo = var_locn_info(VarLocnInfo)
+	),
 	stack__init(ResumePoints),
 	globals__lookup_bool_option(Globals, allow_hijacks, AllowHijack),
 	(
@@ -366,7 +391,7 @@
 		Liveness,
 		InstMap,
 		Zombies,
-		ExprnInfo,
+		VarLocnsInfo,
 		TempsInUse,
 		DummyFailInfo,		% code_info__init_fail_info
 					% will override this dummy value
@@ -379,25 +404,19 @@
 		[],
 		-1
 	),
-	code_info__init_maybe_trace_info(Globals, ModuleInfo, ProcInfo,
-		MaybeFailVars, TraceSlotInfo, CodeInfo0, CodeInfo1),
+	code_info__init_maybe_trace_info(TraceLevel, Globals, TraceSlotInfo,
+		CodeInfo0, CodeInfo1),
 	code_info__init_fail_info(CodeModel, MaybeFailVars, ResumePoint,
 		CodeInfo1, CodeInfo).
 
-:- pred code_info__init_maybe_trace_info(globals, module_info, proc_info,
-	maybe(set(prog_var)), trace_slot_info, code_info, code_info).
-:- mode code_info__init_maybe_trace_info(in, in, in, out, out, in, out) is det.
-
-code_info__init_maybe_trace_info(Globals, ModuleInfo, ProcInfo,
-		MaybeFailVars, TraceSlotInfo) -->
-	{ globals__get_trace_level(Globals, TraceLevel) },
+:- pred code_info__init_maybe_trace_info(trace_level::in, globals::in,
+	trace_slot_info::out, code_info::in, code_info::out) is det.
+
+code_info__init_maybe_trace_info(TraceLevel, Globals, TraceSlotInfo) -->
 	( { TraceLevel \= none } ->
 		trace__setup(Globals, TraceSlotInfo, TraceInfo),
-		code_info__set_maybe_trace_info(yes(TraceInfo)),
-		{ trace__fail_vars(ModuleInfo, ProcInfo, FailVars) },
-		{ MaybeFailVars = yes(FailVars) }
+		code_info__set_maybe_trace_info(yes(TraceInfo))
 	;
-		{ MaybeFailVars = no },
 		{ TraceSlotInfo = trace_slot_info(no, no, no) }
 	).
 
@@ -414,7 +433,7 @@
 code_info__get_forward_live_vars(CI^forward_live_vars, CI, CI).
 code_info__get_instmap(CI^instmap, CI, CI).
 code_info__get_zombies(CI^zombies, CI, CI).
-code_info__get_exprn_info(CI^exprn_info, CI, CI).
+code_info__get_var_locns_info(CI^var_locns_info, CI, CI).
 code_info__get_temps_in_use(CI^temps_in_use, CI, CI).
 code_info__get_fail_info(CI^fail_info, CI, CI).
 code_info__get_label_counter(CI^label_num_src, CI, CI).
@@ -432,7 +451,7 @@
 code_info__set_forward_live_vars(LV, CI, CI^forward_live_vars := LV).
 code_info__set_instmap(IM, CI, CI^instmap := IM).
 code_info__set_zombies(Zs, CI, CI^zombies := Zs).
-code_info__set_exprn_info(EI, CI, CI^exprn_info := EI).
+code_info__set_var_locns_info(EI, CI, CI^var_locns_info := EI).
 code_info__set_temps_in_use(TI, CI, CI^temps_in_use := TI).
 code_info__set_fail_info(FI, CI, CI^fail_info := FI).
 code_info__set_label_counter(LC, CI, CI^label_num_src := LC).
@@ -457,8 +476,13 @@
 
 		% Get the table that contains advice about where
 		% variables should be put.
-:- pred code_info__get_follow_vars(follow_vars, code_info, code_info).
-:- mode code_info__get_follow_vars(out, in, out) is det.
+:- pred code_info__get_follow_var_map(follow_vars_map, code_info, code_info).
+:- mode code_info__get_follow_var_map(out, in, out) is det.
+
+		% Get the integer that gives the number of the next
+		% non-reserved register.
+:- pred code_info__get_next_non_reserved(int, code_info, code_info).
+:- mode code_info__get_next_non_reserved(out, in, out) is det.
 
 		% Set the table that contains advice about where
 		% variables should be put.
@@ -571,17 +595,51 @@
 :- mode code_info__add_resume_layout_for_label(in, in, in, out) is det.
 
 code_info__get_stack_slots(StackSlots, CI, CI) :-
-	code_info__get_exprn_info(ExprnInfo, CI, _),
-	code_exprn__get_stack_slots(StackSlots, ExprnInfo, _).
+	code_info__get_var_locns_info(VarInfo, CI, _),
+	(
+		VarInfo = exprn_info(ExprnInfo),
+		code_exprn__get_stack_slots(StackSlots, ExprnInfo, _)
+	;
+		VarInfo = var_locn_info(VarLocnInfo),
+		var_locn__get_stack_slots(StackSlots, VarLocnInfo, _)
+	).
 
-code_info__get_follow_vars(FollowVars, CI, CI) :-
-	code_info__get_exprn_info(ExprnInfo, CI, _),
-	code_exprn__get_follow_vars(FollowVars, ExprnInfo, _).
+code_info__get_follow_var_map(FollowVarMap, CI, CI) :-
+	code_info__get_var_locns_info(VarInfo, CI, _),
+	(
+		VarInfo = exprn_info(ExprnInfo),
+		code_exprn__get_follow_vars(FollowVars, ExprnInfo, _),
+		FollowVars = follow_vars(FollowVarMap, _)
+	;
+		VarInfo = var_locn_info(VarLocnInfo),
+		var_locn__get_follow_var_map(FollowVarMap, VarLocnInfo, _)
+	).
+
+code_info__get_next_non_reserved(NextNonReserved, CI, CI) :-
+	code_info__get_var_locns_info(VarInfo, CI, _),
+	(
+		VarInfo = exprn_info(ExprnInfo),
+		code_exprn__get_follow_vars(FollowVars, ExprnInfo, _),
+		FollowVars = follow_vars(_, NextNonReserved)
+	;
+		VarInfo = var_locn_info(VarLocnInfo),
+		var_locn__get_next_non_reserved(NextNonReserved, VarLocnInfo,
+			_)
+	).
 
 code_info__set_follow_vars(FollowVars, CI0, CI) :-
-	code_info__get_exprn_info(ExprnInfo0, CI0, _),
+	code_info__get_var_locns_info(VarInfo0, CI0, _),
+	(
+		VarInfo0 = exprn_info(ExprnInfo0),
 	code_exprn__set_follow_vars(FollowVars, ExprnInfo0, ExprnInfo),
-	code_info__set_exprn_info(ExprnInfo, CI0, CI).
+		VarInfo = exprn_info(ExprnInfo)
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		var_locn__set_follow_vars(FollowVars,
+			VarLocnInfo0, VarLocnInfo),
+		VarInfo = var_locn_info(VarLocnInfo)
+	),
+	code_info__set_var_locns_info(VarInfo, CI0, CI).
 
 %-----------------------------------------------------------------------------%
 
@@ -610,7 +668,7 @@
 	% note: we must be careful to apply deaths before births
 	{ goal_info_get_pre_deaths(GoalInfo, PreDeaths) },
 	code_info__rem_forward_live_vars(PreDeaths),
-	code_info__make_vars_forward_dead(PreDeaths),
+	code_info__maybe_make_vars_forward_dead(PreDeaths, no),
 	{ goal_info_get_pre_births(GoalInfo, PreBirths) },
 	code_info__add_forward_live_vars(PreBirths),
 	( { Atomic = yes } ->
@@ -626,7 +684,7 @@
 	% note: we must be careful to apply deaths before births
 	{ goal_info_get_post_deaths(GoalInfo, PostDeaths) },
 	code_info__rem_forward_live_vars(PostDeaths),
-	code_info__make_vars_forward_dead(PostDeaths),
+	code_info__maybe_make_vars_forward_dead(PostDeaths, no),
 	{ goal_info_get_post_births(GoalInfo, PostBirths) },
 	code_info__add_forward_live_vars(PostBirths),
 	code_info__make_vars_forward_live(PostBirths),
@@ -653,7 +711,7 @@
 	{ type_to_type_id(Type, TypeIdPrime, _) ->
 		TypeId = TypeIdPrime
 	;
-		error("unknown type in code_aux__lookup_type_defn")
+		error("unknown type in code_info__lookup_type_defn")
 	},
 	{ module_info_types(ModuleInfo, TypeTable) },
 	{ map__lookup(TypeTable, TypeId, TypeDefn) }.
@@ -854,10 +912,25 @@
 	code_info__set_fail_info(NewFailInfo).
 
 code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd, Code) -->
-	code_info__get_exprn_info(Exprn0),
 	{ map__to_assoc_list(StoreMap, VarLocs) },
-	{ code_exprn__place_vars(VarLocs, Code, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn),
+	code_info__get_var_locns_info(VarInfo),
+	(
+		{ VarInfo = exprn_info(_) }
+	;
+			% The eager code generator generates better code
+			% if it knows in advance where each variable should
+			% go. We don't need to reset the follow_vars
+			% afterwards, since every goal following a branched
+			% control structure must in any case be annotated with
+			% its own follow_var set.
+		{ VarInfo = var_locn_info(_) },
+		{ map__from_assoc_list(VarLocs, FollowVarsMap) },
+		{ assoc_list__values(VarLocs, Locs) },
+		{ code_util__max_mentioned_reg(Locs, MaxMentionedReg) },
+		code_info__set_follow_vars(follow_vars(FollowVarsMap,
+			MaxMentionedReg + 1))
+	),
+	code_info__place_vars(VarLocs, Code),
 	=(EndCodeInfo1),
 	{
 		MaybeEnd0 = no,
@@ -928,10 +1001,10 @@
 		error("no branches in branched control structure")
 	).
 
-	% code_info__remake_with_store_map throws away the exprn_info data
+	% code_info__remake_with_store_map throws away the var_info data
 	% structure, forgetting the current locations of all variables,
 	% and rebuilds it from scratch based on the given store map.
-	% The new exprn_info will know about only the variables present
+	% The new var_info will know about only the variables present
 	% in the store map, and will believe they are where the store map
 	% says they are.
 
@@ -940,18 +1013,19 @@
 
 code_info__remake_with_store_map(StoreMap) -->
 	{ map__to_assoc_list(StoreMap, VarLvals) },
-	{ code_info__fixup_lvallist(VarLvals, VarRvals) },
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__reinit_state(VarRvals, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
-
-:- pred code_info__fixup_lvallist(assoc_list(prog_var, lval),
-		assoc_list(prog_var, rval)).
-:- mode code_info__fixup_lvallist(in, out) is det.
-
-code_info__fixup_lvallist([], []).
-code_info__fixup_lvallist([V - L | Ls], [V - lval(L) | Rs]) :-
-	code_info__fixup_lvallist(Ls, Rs).
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		VarRvals = assoc_list__map_values(exprn_aux__var_lval_to_rval,
+			VarLvals),
+		code_exprn__reinit_state(VarRvals, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		var_locn__reinit_state(VarLvals, VarLocnInfo0, VarLocnInfo),
+		VarInfo = var_locn_info(VarLocnInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
 code_info__save_hp_in_branch(Code, Slot, Pos0, Pos) :-
 	Pos0 = position_info(CodeInfo0),
@@ -1065,6 +1139,8 @@
 :- pred code_info__effect_resume_point(resume_point_info::in, code_model::in,
 	code_tree::out, code_info::in, code_info::out) is det.
 
+:- pred code_info__pop_resume_point(code_info::in, code_info::out) is det.
+
 	% Return the details of the resume point currently on top of the
 	% failure continuation stack.
 
@@ -1186,7 +1262,7 @@
 	% A resume map maps the variables that will be needed at a resumption
 	% point to the locations in which they will be.
 
-:- type resume_map		==	map(prog_var, set(rval)).
+:- type resume_map		==	map(prog_var, set(lval)).
 
 :- type redoip_update		--->	has_been_done
 				;	wont_be_done.
@@ -1535,12 +1611,12 @@
 	code_info__set_fail_info(FailInfo).
 
 :- pred code_info__make_fake_resume_map(list(prog_var)::in,
-	map(prog_var, set(rval))::in, map(prog_var, set(rval))::out) is det.
+	map(prog_var, set(lval))::in, map(prog_var, set(lval))::out) is det.
 
 code_info__make_fake_resume_map([], ResumeMap, ResumeMap).
 code_info__make_fake_resume_map([Var | Vars], ResumeMap0, ResumeMap) :-
 		% a visibly fake location
-	set__singleton_set(Locns, lval(reg(r, -1))),
+	set__singleton_set(Locns, reg(r, -1)),
 	map__det_insert(ResumeMap0, Var, Locns, ResumeMap1),
 	code_info__make_fake_resume_map(Vars, ResumeMap1, ResumeMap).
 
@@ -1911,6 +1987,15 @@
 		CurfrMaxfr, CondEnv, Allow) },
 	code_info__set_fail_info(FailInfo).
 
+code_info__pop_resume_point -->
+	code_info__get_fail_info(FailInfo0),
+	{ FailInfo0 = fail_info(ResumePoints0, ResumeKnown, CurfrMaxfr,
+		CondEnv, Allow) },
+	{ stack__pop_det(ResumePoints0, _, ResumePoints) },
+	{ FailInfo = fail_info(ResumePoints, ResumeKnown, CurfrMaxfr,
+		CondEnv, Allow) },
+	code_info__set_fail_info(FailInfo).
+
 %---------------------------------------------------------------------------%
 
 code_info__top_resume_point(ResumePoint) -->
@@ -1951,7 +2036,7 @@
 				Map, FailureAddress) },
 			{ map__to_assoc_list(Map, AssocList) },
 			code_info__remember_position(CurPos),
-			code_info__place_vars(AssocList, PlaceCode),
+			code_info__pick_and_place_vars(AssocList, PlaceCode),
 			code_info__reset_to_position(CurPos)
 		),
 		{ BranchCode = node([goto(FailureAddress) - "fail"]) },
@@ -1983,7 +2068,7 @@
 			{ map__to_assoc_list(Map, AssocList) },
 			code_info__get_next_label(SuccessLabel),
 			code_info__remember_position(CurPos),
-			code_info__place_vars(AssocList, PlaceCode),
+			code_info__pick_and_place_vars(AssocList, PlaceCode),
 			code_info__reset_to_position(CurPos),
 			{ SuccessAddress = label(SuccessLabel) },
 				% We branch away if the test *fails*,
@@ -2050,35 +2135,35 @@
 	code_addr::out, code_info::in, code_info::out) is semidet.
 
 code_info__pick_matching_resume_addr(ResumeMaps, Addr) -->
-	code_info__variable_locations(Locations),
+	code_info__variable_locations(CurLocs),
 	{
 		ResumeMaps = orig_only(Map1, Addr1),
-		( code_info__match_resume_loc(Map1, Locations) ->
+		( code_info__match_resume_loc(Map1, CurLocs) ->
 			Addr = Addr1
 		;
 			fail
 		)
 	;
 		ResumeMaps = stack_only(Map1, Addr1),
-		( code_info__match_resume_loc(Map1, Locations) ->
+		( code_info__match_resume_loc(Map1, CurLocs) ->
 			Addr = Addr1
 		;
 			fail
 		)
 	;
 		ResumeMaps = orig_and_stack(Map1, Addr1, Map2, Addr2),
-		( code_info__match_resume_loc(Map1, Locations) ->
+		( code_info__match_resume_loc(Map1, CurLocs) ->
 			Addr = Addr1
-		; code_info__match_resume_loc(Map2, Locations) ->
+		; code_info__match_resume_loc(Map2, CurLocs) ->
 			Addr = Addr2
 		;
 			fail
 		)
 	;
 		ResumeMaps = stack_and_orig(Map1, Addr1, Map2, Addr2),
-		( code_info__match_resume_loc(Map1, Locations) ->
+		( code_info__match_resume_loc(Map1, CurLocs) ->
 			Addr = Addr1
-		; code_info__match_resume_loc(Map2, Locations) ->
+		; code_info__match_resume_loc(Map2, CurLocs) ->
 			Addr = Addr2
 		;
 			fail
@@ -2095,8 +2180,8 @@
 	\+ (
 		list__member(Var - Actual, List),
 		\+ (
-			map__search(Map, Var, Rvals),
-			set__subset(Rvals, Actual)
+			map__search(Map, Var, Lvals),
+			set__subset(Lvals, Actual)
 		)
 	).
 
@@ -2135,16 +2220,16 @@
 	code_info__produce_vars_2(VarList, Map, Code).
 
 :- pred code_info__produce_vars_2(list(prog_var)::in,
-	map(prog_var, set(rval))::out,
+	map(prog_var, set(lval))::out,
 	code_tree::out, code_info::in, code_info::out) is det.
 
 code_info__produce_vars_2([], Map, empty) -->
 	{ map__init(Map) }.
 code_info__produce_vars_2([V | Vs], Map, Code) -->
 	code_info__produce_vars_2(Vs, Map0, Code0),
-	code_info__produce_variable_in_reg_or_stack(V, Code1, Rval),
-	{ set__singleton_set(Rvals, Rval) },
-	{ map__set(Map0, V, Rvals, Map) },
+	code_info__produce_variable_in_reg_or_stack(V, Code1, Lval),
+	{ set__singleton_set(Lvals, Lval) },
+	{ map__set(Map0, V, Lvals, Map) },
 	{ Code = tree(Code0, Code1) }.
 
 code_info__flush_resume_vars_to_stack(Code) -->
@@ -2153,7 +2238,7 @@
 	{ stack__top_det(ResumePointStack, ResumePoint) },
 	{ code_info__pick_stack_resume_point(ResumePoint, StackMap, _) },
 	{ map__to_assoc_list(StackMap, StackLocs) },
-	code_info__place_vars(StackLocs, Code).
+	code_info__pick_and_place_vars(StackLocs, Code).
 
 %---------------------------------------------------------------------------%
 
@@ -2250,11 +2335,11 @@
 	).
 
 :- pred code_info__make_singleton_sets(assoc_list(prog_var, lval)::in,
-	assoc_list(prog_var, set(rval))::out) is det.
+	assoc_list(prog_var, set(lval))::out) is det.
 
 code_info__make_singleton_sets([], []).
-code_info__make_singleton_sets([V - L | Rest0], [V - Rs | Rest]) :-
-	set__singleton_set(Rs, lval(L)),
+code_info__make_singleton_sets([V - L | Rest0], [V - Ls | Rest]) :-
+	set__singleton_set(Ls, L),
 	code_info__make_singleton_sets(Rest0, Rest).
 
 %---------------------------------------------------------------------------%
@@ -2352,7 +2437,7 @@
 		error("extract_label_from_code_addr: non-label!")
 	).
 
-:- pred code_info__place_resume_vars(assoc_list(prog_var, set(rval))::in,
+:- pred code_info__place_resume_vars(assoc_list(prog_var, set(lval))::in,
 	code_tree::out, code_info::in, code_info::out) is det.
 
 code_info__place_resume_vars([], empty) --> [].
@@ -2362,18 +2447,14 @@
 	{ Code = tree(FirstCode, RestCode) },
 	code_info__place_resume_vars(Rest, RestCode).
 
-:- pred code_info__place_resume_var(prog_var::in, list(rval)::in,
+:- pred code_info__place_resume_var(prog_var::in, list(lval)::in,
 	code_tree::out, code_info::in, code_info::out) is det.
 
 code_info__place_resume_var(_Var, [], empty) --> [].
 code_info__place_resume_var(Var, [Target | Targets], Code) -->
-	( { Target = lval(TargetLval) } ->
-		code_info__place_var(Var, TargetLval, FirstCode)
-	;
-		{ error("code_info__place_resume_var: not lval") }
-	),
-	{ Code = tree(FirstCode, RestCode) },
-	code_info__place_resume_var(Var, Targets, RestCode).
+	code_info__place_var(Var, Target, FirstCode),
+	code_info__place_resume_var(Var, Targets, RestCode),
+	{ Code = tree(FirstCode, RestCode) }.
 
 	% Reset the code generator's database of what is where.
 	% Remember that the variables in the map are available in their
@@ -2383,14 +2464,24 @@
 	code_info::in, code_info::out) is det.
 
 code_info__set_var_locations(Map) -->
-	{ map__to_assoc_list(Map, List0) },
-	{ code_info__flatten_varlval_list(List0, List) },
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__reinit_state(List, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+	{ map__to_assoc_list(Map, LvalList0) },
+	{ code_info__flatten_varlval_list(LvalList0, LvalList) },
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		RvalList = assoc_list__map_values(exprn_aux__var_lval_to_rval,
+			LvalList),
+		code_exprn__reinit_state(RvalList, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		var_locn__reinit_state(LvalList, VarLocnInfo0, VarLocnInfo),
+		VarInfo = var_locn_info(VarLocnInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
-:- pred code_info__flatten_varlval_list(assoc_list(prog_var, set(rval))::in,
-	assoc_list(prog_var, rval)::out) is det.
+:- pred code_info__flatten_varlval_list(assoc_list(prog_var, set(lval))::in,
+	assoc_list(prog_var, lval)::out) is det.
 
 code_info__flatten_varlval_list([], []).
 code_info__flatten_varlval_list([V - Rvals | Rest0], All) :-
@@ -2399,8 +2490,8 @@
 	code_info__flatten_varlval_list_2(RvalList, V, Rest1),
 	list__append(Rest1, Rest, All).
 
-:- pred code_info__flatten_varlval_list_2(list(rval)::in, prog_var::in,
-	assoc_list(prog_var, rval)::out) is det.
+:- pred code_info__flatten_varlval_list_2(list(lval)::in, prog_var::in,
+	assoc_list(prog_var, lval)::out) is det.
 
 code_info__flatten_varlval_list_2([], _V, []).
 code_info__flatten_varlval_list_2([R | Rs], V, [V - R | Rest]) :-
@@ -2553,40 +2644,81 @@
 
 code_info__make_vars_forward_live(Vars) -->
 	code_info__get_stack_slots(StackSlots),
-	code_info__get_exprn_info(Exprn0),
+	code_info__get_var_locns_info(VarInfo0),
 	{ set__to_sorted_list(Vars, VarList) },
 	{ code_info__make_vars_forward_live_2(VarList, StackSlots, 1,
-		Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+		VarInfo0, VarInfo) },
+	code_info__set_var_locns_info(VarInfo).
 
 :- pred code_info__make_vars_forward_live_2(list(prog_var), stack_slots, int,
-	exprn_info, exprn_info).
+	var_locns_info, var_locns_info).
 :- mode code_info__make_vars_forward_live_2(in, in, in, in, out) is det.
 
-code_info__make_vars_forward_live_2([], _, _, Exprn, Exprn).
-code_info__make_vars_forward_live_2([V | Vs], StackSlots, N0, Exprn0, Exprn) :-
-	( map__search(StackSlots, V, Lval0) ->
+code_info__make_vars_forward_live_2([], _, _, VarInfo, VarInfo).
+code_info__make_vars_forward_live_2([Var | Vars], StackSlots, N0,
+		VarInfo0, VarInfo) :-
+	( map__search(StackSlots, Var, Lval0) ->
 		Lval = Lval0,
 		N1 = N0
 	;
-		code_info__find_unused_reg(N0, Exprn0, N1),
+		code_info__find_unused_reg(N0, VarInfo0, N1),
 		Lval = reg(r, N1)
 	),
-	code_exprn__maybe_set_var_location(V, Lval, Exprn0, Exprn1),
-	code_info__make_vars_forward_live_2(Vs, StackSlots, N1, Exprn1, Exprn).
+	(
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__maybe_set_var_location(Var, Lval, Exprn0, Exprn1),
+		VarInfo1 = exprn_info(Exprn1)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__set_magic_var_location(Var, Lval,
+			VarLocn0, VarLocn1),
+		VarInfo1 = var_locn_info(VarLocn1)
+	),
+	code_info__make_vars_forward_live_2(Vars, StackSlots, N1,
+		VarInfo1, VarInfo).
 
-:- pred code_info__find_unused_reg(int, exprn_info, int).
+:- pred code_info__find_unused_reg(int, var_locns_info, int).
 :- mode code_info__find_unused_reg(in, in, out) is det.
+
+code_info__find_unused_reg(N0, VarInfo0, N) :-
+	(
+		VarInfo0 = exprn_info(Exprn0),
+		code_info__find_unused_reg_lazy(N0, Exprn0, N)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		code_info__find_unused_reg_eager(N0, VarLocn0, N)
+	).
+
+:- pred code_info__find_unused_reg_eager(int, var_locn_info, int).
+:- mode code_info__find_unused_reg_eager(in, in, out) is det.
+
+code_info__find_unused_reg_eager(N0, Exprn0, N) :-
+	( var_locn__lval_in_use(reg(r, N0), Exprn0, _) ->
+		N1 is N0 + 1,
+		code_info__find_unused_reg_eager(N1, Exprn0, N)
+	;
+		N = N0
+	).
 
-code_info__find_unused_reg(N0, Exprn0, N) :-
+:- pred code_info__find_unused_reg_lazy(int, exprn_info, int).
+:- mode code_info__find_unused_reg_lazy(in, in, out) is det.
+
+code_info__find_unused_reg_lazy(N0, Exprn0, N) :-
 	( code_exprn__lval_in_use(reg(r, N0), Exprn0, _) ->
 		N1 is N0 + 1,
-		code_info__find_unused_reg(N1, Exprn0, N)
+		code_info__find_unused_reg_lazy(N1, Exprn0, N)
 	;
 		N = N0
 	).
+
+code_info__make_vars_forward_dead(Vars) -->
+	code_info__maybe_make_vars_forward_dead(Vars, yes).
 
-code_info__make_vars_forward_dead(Vars0) -->
+:- pred code_info__maybe_make_vars_forward_dead(set(prog_var), bool,
+	code_info, code_info).
+:- mode code_info__maybe_make_vars_forward_dead(in, in, in, out) is det.
+
+code_info__maybe_make_vars_forward_dead(Vars0, FirstTime) -->
 	code_info__current_resume_point_vars(ResumeVars),
 	{ set__intersect(Vars0, ResumeVars, FlushVars) },
 	code_info__get_zombies(Zombies0),
@@ -2594,18 +2726,26 @@
 	code_info__set_zombies(Zombies),
 	{ set__difference(Vars0, Zombies, Vars) },
 	{ set__to_sorted_list(Vars, VarList) },
-	code_info__make_vars_forward_dead_2(VarList).
+	code_info__maybe_make_vars_forward_dead_2(VarList, FirstTime).
 
-:- pred code_info__make_vars_forward_dead_2(list(prog_var),
+:- pred code_info__maybe_make_vars_forward_dead_2(list(prog_var), bool,
 		code_info, code_info).
-:- mode code_info__make_vars_forward_dead_2(in, in, out) is det.
+:- mode code_info__maybe_make_vars_forward_dead_2(in, in, in, out) is det.
 
-code_info__make_vars_forward_dead_2([]) --> [].
-code_info__make_vars_forward_dead_2([V | Vs]) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__var_becomes_dead(V, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn),
-	code_info__make_vars_forward_dead_2(Vs).
+code_info__maybe_make_vars_forward_dead_2([], _) --> [].
+code_info__maybe_make_vars_forward_dead_2([V | Vs], FirstTime) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__var_becomes_dead(V, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__var_becomes_dead(V, FirstTime, VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo),
+	code_info__maybe_make_vars_forward_dead_2(Vs, FirstTime).
 
 code_info__pickup_zombies(Zombies) -->
 	code_info__get_zombies(Zombies),
@@ -2867,53 +3007,56 @@
 
 :- interface.
 
-:- pred code_info__variable_locations(map(prog_var, set(rval)),
-	code_info, code_info).
-:- mode code_info__variable_locations(out, in, out) is det.
+:- pred code_info__variable_locations(map(prog_var, set(lval))::out,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__set_var_location(prog_var, lval, code_info, code_info).
-:- mode code_info__set_var_location(in, in, in, out) is det.
+:- pred code_info__set_var_location(prog_var::in, lval::in,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__cache_expression(prog_var, rval, code_info, code_info).
-:- mode code_info__cache_expression(in, in, in, out) is det.
+:- pred code_info__assign_var_to_var(prog_var::in, prog_var::in,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__place_var(prog_var, lval, code_tree, code_info, code_info).
-:- mode code_info__place_var(in, in, out, in, out) is det.
+:- pred code_info__assign_lval_to_var(prog_var::in, lval::in,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__produce_variable(prog_var, code_tree, rval,
-		code_info, code_info).
-:- mode code_info__produce_variable(in, out, out, in, out) is det.
+:- pred code_info__assign_const_to_var(prog_var::in, rval::in,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__produce_variable_in_reg(prog_var, code_tree, rval,
-	code_info, code_info).
-:- mode code_info__produce_variable_in_reg(in, out, out, in, out) is det.
+:- pred code_info__assign_expr_to_var(prog_var::in, rval::in, code_tree::out,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__produce_variable_in_reg_or_stack(prog_var, code_tree, rval,
-	code_info, code_info).
-:- mode code_info__produce_variable_in_reg_or_stack(in, out, out, in, out)
-	is det.
+:- pred code_info__assign_cell_to_var(prog_var::in, tag::in,
+	list(maybe(rval))::in, string::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+:- pred code_info__place_var(prog_var::in, lval::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+:- pred code_info__produce_variable(prog_var::in, code_tree::out, rval::out,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__materialize_vars_in_rval(rval, rval, code_tree, code_info,
-	code_info).
-:- mode code_info__materialize_vars_in_rval(in, out, out, in, out) is det.
+:- pred code_info__produce_variable_in_reg(prog_var::in, code_tree::out,
+	lval::out, code_info::in, code_info::out) is det.
 
-:- pred code_info__lock_reg(lval, code_info, code_info).
-:- mode code_info__lock_reg(in, in, out) is det.
+:- pred code_info__produce_variable_in_reg_or_stack(prog_var::in,
+	code_tree::out, lval::out, code_info::in, code_info::out) is det.
 
-:- pred code_info__unlock_reg(lval, code_info, code_info).
-:- mode code_info__unlock_reg(in, in, out) is det.
+:- pred code_info__materialize_vars_in_rval(rval::in, rval::out,
+	code_tree::out, code_info::in, code_info::out) is det.
 
-:- pred code_info__acquire_reg_for_var(prog_var, lval, code_info, code_info).
-:- mode code_info__acquire_reg_for_var(in, out, in, out) is det.
+:- pred code_info__acquire_reg_for_var(prog_var::in, lval::out,
+	code_info::in, code_info::out) is det.
+
+:- pred code_info__acquire_reg(reg_type::in, lval::out,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__acquire_reg(reg_type, lval, code_info, code_info).
-:- mode code_info__acquire_reg(in, out, in, out) is det.
+:- pred code_info__release_reg(lval::in, code_info::in, code_info::out) is det.
 
-:- pred code_info__release_reg(lval, code_info, code_info).
-:- mode code_info__release_reg(in, in, out) is det.
+:- pred code_info__reserve_r1(code_tree::out, code_info::in, code_info::out)
+	is det.
 
-:- pred code_info__clear_r1(code_tree, code_info, code_info).
-:- mode code_info__clear_r1(out, in, out) is det.
+:- pred code_info__clear_r1(code_tree::out, code_info::in, code_info::out)
+	is det.
 
 :- type call_direction ---> caller ; callee.
 
@@ -2921,150 +3064,430 @@
 	% (i.e. in the caller), or to setup the output arguments in the
 	% predicate epilog (i.e. in the callee).
 
-:- pred code_info__setup_call(assoc_list(prog_var, arg_info),
-	call_direction, code_tree, code_info, code_info).
-:- mode code_info__setup_call(in, in, out, in, out) is det.
+:- pred code_info__setup_call(assoc_list(prog_var, arg_info)::in,
+	call_direction::in, code_tree::out,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__clear_all_registers(code_info, code_info).
-:- mode code_info__clear_all_registers(in, out) is det.
+:- pred code_info__eager_lock_regs(int::in, assoc_list(prog_var, lval)::in,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__save_variable_on_stack(prog_var, code_tree,
-	code_info, code_info).
-:- mode code_info__save_variable_on_stack(in, out, in, out) is det.
+:- pred code_info__eager_unlock_regs(code_info::in, code_info::out) is det.
 
-:- pred code_info__save_variables_on_stack(list(prog_var), code_tree,
-	code_info, code_info).
-:- mode code_info__save_variables_on_stack(in, out, in, out) is det.
+:- pred code_info__clear_all_registers(code_info::in, code_info::out) is det.
 
-:- pred code_info__max_reg_in_use(int, code_info, code_info).
-:- mode code_info__max_reg_in_use(out, in, out) is det.
+:- pred code_info__clobber_regs(list(lval)::in,
+	code_info::in, code_info::out) is det.
 
+:- pred code_info__save_variables(set(prog_var)::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+:- pred code_info__save_variable_on_stack(prog_var::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+:- pred code_info__save_variables_on_stack(list(prog_var)::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+:- pred code_info__max_reg_in_use(int::out, code_info::in, code_info::out)
+	is det.
+
 %---------------------------------------------------------------------------%
 
 :- implementation.
 
-:- pred code_info__place_vars(assoc_list(prog_var, set(rval)), code_tree,
-	code_info, code_info).
-:- mode code_info__place_vars(in, out, in, out) is det.
+:- pred code_info__pick_and_place_vars(assoc_list(prog_var, set(lval))::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
-code_info__variable_locations(Locations) -->
-	code_info__get_exprn_info(Exprn),
-	{ code_exprn__get_varlocs(Exprn, Locations) }.
+:- pred code_info__place_vars(assoc_list(prog_var, lval)::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
+code_info__variable_locations(Lvals) -->
+	code_info__get_var_locns_info(VarInfo),
+	{
+		VarInfo = exprn_info(Exprn),
+		code_exprn__get_varlocs(Exprn, Rvals),
+		Lvals = map__map_values(code_info__rval_map_to_lval_map, Rvals)
+	;
+		VarInfo = var_locn_info(VarLocn),
+		var_locn__get_var_locations(VarLocn, Lvals)
+	}.
+
+:- func code_info__rval_map_to_lval_map(prog_var, set(rval)) = set(lval).
+
+code_info__rval_map_to_lval_map(_Var, Rvals) =
+	set__filter_map(code_info__rval_is_lval, Rvals).
+
+:- func code_info__rval_is_lval(rval) = lval is semidet.
+
+code_info__rval_is_lval(lval(Lval)) = Lval.
+
 code_info__set_var_location(Var, Lval) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__set_var_location(Var, Lval, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
-
-code_info__cache_expression(Var, Rval) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__cache_exprn(Var, Rval, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__set_var_location(Var, Lval, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__check_and_set_magic_var_location(Var, Lval,
+			VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
-code_info__place_var(Var, Lval, Code) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__place_var(Var, Lval, Code, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+code_info__assign_var_to_var(Var, AssignedVar) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__cache_exprn(Var, var(AssignedVar), Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocInfo0),
+		var_locn__assign_var_to_var(Var, AssignedVar,
+			VarLocInfo0, VarLocInfo),
+		VarInfo = var_locn_info(VarLocInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
-code_info__place_vars([], empty) --> [].
-code_info__place_vars([V - Rs | RestList], Code) -->
-	(
-		{ set__to_sorted_list(Rs, RList) },
-		{ code_info__lval_in_rval_list(L, RList) }
+code_info__assign_lval_to_var(Var, Lval) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__cache_exprn(Var, lval(Lval), Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocInfo0),
+		var_locn__assign_lval_to_var(Var, Lval,
+			VarLocInfo0, VarLocInfo),
+		VarInfo = var_locn_info(VarLocInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
+code_info__assign_const_to_var(Var, ConstRval) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__cache_exprn(Var, ConstRval, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocInfo0),
+		var_locn__assign_const_to_var(Var, ConstRval,
+			VarLocInfo0, VarLocInfo),
+		VarInfo = var_locn_info(VarLocInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
+code_info__assign_expr_to_var(Var, Rval, Code) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		code_util__lvals_in_rval(Rval, Lvals),
+		Lvals = []
 	->
-		code_info__place_var(V, L, ThisCode)
+		(
+			VarInfo0 = exprn_info(Exprn0),
+			code_exprn__cache_exprn(Var, Rval, Exprn0, Exprn),
+			VarInfo = exprn_info(Exprn),
+			Code = empty
+		;
+			VarInfo0 = var_locn_info(VarLocInfo0),
+			var_locn__assign_expr_to_var(Var, Rval, Code,
+				VarLocInfo0, VarLocInfo),
+			VarInfo = var_locn_info(VarLocInfo)
+		)
 	;
-		{ ThisCode = empty }
-	),
-	code_info__place_vars(RestList, RestCode),
-	{ Code = tree(ThisCode, RestCode) }.
+		error("code_info__assign_expr_to_var: non-var lvals")
+	},
+	code_info__set_var_locns_info(VarInfo).
+
+code_info__assign_cell_to_var(Var, Ptag, Vector, TypeMsg, Code) -->
+	code_info__get_var_locns_info(VarInfo0),
+	code_info__get_next_cell_number(CellNum),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+			% XXX Later we will need to worry about
+			% whether the cell must be unique or not.
+		Reuse = no,
+		Rval = create(Ptag, Vector, uniform(no), can_be_either,
+			CellNum, TypeMsg, Reuse),
+		code_exprn__cache_exprn(Var, Rval, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn),
+		Code = empty
+	;
+		VarInfo0 = var_locn_info(VarLocInfo0),
+		var_locn__assign_cell_to_var(Var, Ptag, Vector, CellNum,
+			TypeMsg, Code, VarLocInfo0, VarLocInfo),
+		VarInfo = var_locn_info(VarLocInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
+code_info__place_var(Var, Lval, Code) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__place_var(Var, Lval, Code, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__place_var(Var, Lval, Code, VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
-:- pred code_info__lval_in_rval_list(lval, list(rval)).
-:- mode code_info__lval_in_rval_list(out, in) is semidet.
+code_info__pick_and_place_vars(VarLocSets, Code) -->
+	{ code_info__pick_var_places(VarLocSets, VarLocs) },
+	code_info__place_vars(VarLocs, Code).
 
-code_info__lval_in_rval_list(Lval, [Rval | Rvals]) :-
-	( Rval = lval(Lval0) ->
-		Lval = Lval0
+:- pred code_info__pick_var_places(assoc_list(prog_var, set(lval))::in,
+	assoc_list(prog_var, lval)::out) is det.
+
+code_info__pick_var_places([], []).
+code_info__pick_var_places([Var - LvalSet | VarLvalSets], VarLvals) :-
+	code_info__pick_var_places(VarLvalSets, VarLvals0),
+	(
+		set__to_sorted_list(LvalSet, LvalList),
+		LvalList = [Lval | _]
+	->
+		VarLvals = [Var - Lval | VarLvals0]
 	;
-		code_info__lval_in_rval_list(Lval, Rvals)
+		VarLvals = VarLvals0
 	).
 
+code_info__place_vars(VarLocs, Code) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__place_vars(VarLocs, Code, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__place_vars(VarLocs, Code, VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
 code_info__produce_variable(Var, Code, Rval) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__produce_var(Var, Rval, Code, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
-
-code_info__produce_variable_in_reg(Var, Code, Rval) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__produce_var_in_reg(Var, Rval, Code, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
-
-code_info__produce_variable_in_reg_or_stack(Var, Code, Rval) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__produce_var_in_reg_or_stack(Var, Rval, Code,
-		Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__produce_var(Var, Rval, Code, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__produce_var(Var, Rval, Code, VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
+code_info__produce_variable_in_reg(Var, Code, Lval) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__produce_var_in_reg(Var, Lval, Code, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__produce_var_in_reg(Var, Lval, Code,
+			VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
+code_info__produce_variable_in_reg_or_stack(Var, Code, Lval) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__produce_var_in_reg_or_stack(Var, Lval, Code,
+			Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__produce_var_in_reg_or_stack(Var, Lval, Code,
+			VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
 code_info__materialize_vars_in_rval(Rval0, Rval, Code) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__materialize_vars_in_rval(Rval0, Rval, Code,
-		Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
-
-code_info__lock_reg(Reg) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__lock_reg(Reg, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
-
-code_info__unlock_reg(Reg) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__unlock_reg(Reg, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__materialize_vars_in_rval(Rval0, Rval, Code,
+			Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		( Rval0 = lval(Lval0) ->
+			var_locn__materialize_vars_in_lval(Lval0, Lval,
+				VarLocnInfo0, VarLocnInfo),
+			Rval = lval(Lval),
+			Code = empty,
+			VarInfo = var_locn_info(VarLocnInfo)
+		; exprn_aux__vars_in_rval(Rval0, []) ->
+			Rval = Rval0,
+			Code = empty,
+			VarInfo = VarInfo0
+		;
+			error("eager code_info__materialize_vars_in_rval")
+		)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
 code_info__acquire_reg_for_var(Var, Lval) -->
-	code_info__get_exprn_info(Exprn0),
-	code_info__get_follow_vars(Follow),
-	(
-		{ map__search(Follow, Var, PrefLval) },
-		{ PrefLval = reg(PrefRegType, PrefRegNum) }
+	code_info__get_follow_var_map(FollowVarsMap),
+	code_info__get_next_non_reserved(NextNonReserved),
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		map__search(FollowVarsMap, Var, PrefLval),
+		PrefLval = reg(PrefRegType, PrefRegNum),
+		PrefRegNum >= 1
 	->
-		{ code_exprn__acquire_reg_prefer_given(PrefRegType, PrefRegNum,
-			Lval, Exprn0, Exprn) }
+		(
+			VarInfo0 = exprn_info(Exprn0),
+			code_exprn__acquire_reg_prefer_given(PrefRegType,
+				PrefRegNum, Lval, Exprn0, Exprn),
+			VarInfo = exprn_info(Exprn)
+		;
+			VarInfo0 = var_locn_info(VarLocn0),
+			require(unify(PrefRegType, r), "acquire non-r reg"),
+			var_locn__acquire_reg_prefer_given(PrefRegNum, Lval,
+				VarLocn0, VarLocn),
+			VarInfo = var_locn_info(VarLocn)
+		)
 	;
-		{ code_exprn__acquire_reg(r, Lval, Exprn0, Exprn) }
-	),
-	code_info__set_exprn_info(Exprn).
+		% XXX We should only get a register if the map__search
+		% succeeded; otherwise we should put the var in its stack slot.
+		(
+			VarInfo0 = exprn_info(Exprn0),
+			code_exprn__acquire_reg(r, Lval, Exprn0, Exprn),
+			VarInfo = exprn_info(Exprn)
+		;
+			VarInfo0 = var_locn_info(VarLocn0),
+			var_locn__acquire_reg_start_at_given(
+				NextNonReserved,Lval, VarLocn0, VarLocn),
+			VarInfo = var_locn_info(VarLocn)
+		)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
 code_info__acquire_reg(Type, Lval) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__acquire_reg(Type, Lval, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__acquire_reg(Type, Lval, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		require(unify(Type, r),
+			"code_info__acquire_reg: unknown reg type"),
+		var_locn__acquire_reg(Lval, VarLocnInfo0, VarLocnInfo),
+		VarInfo = var_locn_info(VarLocnInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
 code_info__release_reg(Lval) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__release_reg(Lval, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__release_reg(Lval, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		var_locn__release_reg(Lval, VarLocnInfo0, VarLocnInfo),
+		VarInfo = var_locn_info(VarLocnInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
+code_info__reserve_r1(Code) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(_Exprn0),
+		VarInfo = VarInfo0,
+		Code = empty
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		var_locn__clear_r1(Code, VarLocnInfo0, VarLocnInfo1),
+		var_locn__acquire_reg_require_given(reg(r, 1), VarLocnInfo1,
+			VarLocnInfo),
+		VarInfo = var_locn_info(VarLocnInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
 code_info__clear_r1(Code) -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__clear_r1(Code, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__clear_r1(Code, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		var_locn__release_reg(reg(r, 1), VarLocnInfo0, VarLocnInfo),
+		VarInfo = var_locn_info(VarLocnInfo),
+		Code = empty
+	},
+	code_info__set_var_locns_info(VarInfo).
 
 %---------------------------------------------------------------------------%
 
-code_info__setup_call([], _Direction, empty) --> [].
-code_info__setup_call([V - arg_info(Loc, Mode) | Rest], Direction, Code) -->
+code_info__setup_call(VarArgInfos, Direction, Code) -->
+	code_info__get_var_locns_info(VarInfo0),
 	(
-		{
-			Mode = top_in,
-			Direction = caller
+		{ VarInfo0 = exprn_info(_) },
+		code_info__setup_call_lazy(VarArgInfos, Direction, Code)
 		;
-			Mode = top_out,
-			Direction = callee
-		}
-	->
+		{ VarInfo0 = var_locn_info(_) },
+		code_info__setup_call_eager(VarArgInfos, Direction, Code)
+	).
+
+:- pred code_info__setup_call_eager(assoc_list(prog_var, arg_info)::in,
+	call_direction::in, code_tree::out, code_info::in, code_info::out)
+	is det.
+
+code_info__setup_call_eager(AllArgsInfos, Direction, Code) -->
+	{ list__filter(code_info__call_arg_in_selected_dir(Direction),
+		AllArgsInfos, ArgsInfos) },
+	{ code_info__var_arg_info_to_lval(ArgsInfos, ArgsLocns) },
+	code_info__get_eager_var_locns_info(VarLocnInfo0),
+	{ var_locn__place_vars(ArgsLocns, Code, VarLocnInfo0, VarLocnInfo1) },
+	code_info__set_var_locns_info(var_locn_info(VarLocnInfo1)),
+	{ assoc_list__keys(ArgsLocns, ArgVars) },
+	{ set__init(DeadVars0) },
+	code_info__which_variables_are_forward_live(ArgVars,
+		DeadVars0, DeadVars),
+	code_info__make_vars_forward_dead(DeadVars).
+
+:- pred code_info__var_arg_info_to_lval(assoc_list(prog_var, arg_info)::in,
+	assoc_list(prog_var, lval)::out) is det.
+
+code_info__var_arg_info_to_lval([], []).
+code_info__var_arg_info_to_lval([Var - ArgInfo | RestInfos],
+		[Var - Lval | RestLvals]) :-
+	ArgInfo = arg_info(Loc, _Mode),
+	code_util__arg_loc_to_register(Loc, Lval),
+	code_info__var_arg_info_to_lval(RestInfos, RestLvals).
+
+:- pred code_info__which_variables_are_forward_live(list(prog_var)::in,
+	set(prog_var)::in, set(prog_var)::out,
+	code_info::in, code_info::out) is det.
+
+code_info__which_variables_are_forward_live([], DeadVars, DeadVars) --> [].
+code_info__which_variables_are_forward_live([Var | Vars], DeadVars0, DeadVars)
+		-->
+	( code_info__variable_is_forward_live(Var) ->
+		{ DeadVars1 = DeadVars0 }
+	;
+		{ set__insert(DeadVars0, Var, DeadVars1) }
+	),
+	code_info__which_variables_are_forward_live(Vars, DeadVars1, DeadVars).
+
+:- pred code_info__setup_call_lazy(assoc_list(prog_var, arg_info)::in,
+	call_direction::in, code_tree::out, code_info::in, code_info::out)
+	is det.
+
+code_info__setup_call_lazy([], _Direction, empty) --> [].
+code_info__setup_call_lazy([First | Rest], Direction, Code) -->
+	( { code_info__call_arg_in_selected_dir(Direction, First) } ->
+		{ First = V - arg_info(Loc, _Mode) },
 		{ code_util__arg_loc_to_register(Loc, Reg) },
-		code_info__get_exprn_info(Exprn0),
+		code_info__get_lazy_var_locns_info(Exprn0),
 		{ code_exprn__place_var(V, Reg, Code0, Exprn0, Exprn1) },
 			% We need to test that either the variable
 			% is live OR it occurs in the remaining arguments
@@ -3092,39 +3515,159 @@
 			{ bool__or(Occurs, IsLive, yes) }
 		->
 			{ code_exprn__lock_reg(Reg, Exprn1, Exprn2) },
-			code_info__set_exprn_info(Exprn2),
-			code_info__setup_call(Rest, Direction, Code1),
-			code_info__get_exprn_info(Exprn3),
+			code_info__set_var_locns_info(exprn_info(Exprn2)),
+			code_info__setup_call_lazy(Rest, Direction, Code1),
+			code_info__get_lazy_var_locns_info(Exprn3),
 			{ code_exprn__unlock_reg(Reg, Exprn3, Exprn) },
-			code_info__set_exprn_info(Exprn),
+			code_info__set_var_locns_info(exprn_info(Exprn)),
 			{ Code = tree(Code0, Code1) }
 		;
 			{ code_exprn__lock_reg(Reg, Exprn1, Exprn2) },
-			code_info__set_exprn_info(Exprn2),
+			code_info__set_var_locns_info(exprn_info(Exprn2)),
 			{ set__singleton_set(Vset, V) },
 			code_info__make_vars_forward_dead(Vset),
-			code_info__setup_call(Rest, Direction, Code1),
-			code_info__get_exprn_info(Exprn4),
+			code_info__setup_call_lazy(Rest, Direction, Code1),
+			code_info__get_lazy_var_locns_info(Exprn4),
 			{ code_exprn__unlock_reg(Reg, Exprn4, Exprn) },
-			code_info__set_exprn_info(Exprn),
+			code_info__set_var_locns_info(exprn_info(Exprn)),
 			{ Code = tree(Code0, Code1) }
 		)
+	;
+		code_info__setup_call_lazy(Rest, Direction, Code)
+	).
+
+:- pred code_info__call_arg_in_selected_dir(call_direction::in,
+	pair(prog_var, arg_info)::in) is semidet.
+
+code_info__call_arg_in_selected_dir(Direction, _ - arg_info(_, Mode)) :-
+	(
+		Mode = top_in,
+		Direction = caller
 	;
-		code_info__setup_call(Rest, Direction, Code)
+		Mode = top_out,
+		Direction = callee
 	).
 
+code_info__eager_lock_regs(N, Exceptions) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(_),
+		VarInfo = VarInfo0
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		var_locn__lock_regs(N, Exceptions, VarLocnInfo0, VarLocnInfo),
+		VarInfo = var_locn_info(VarLocnInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
+code_info__eager_unlock_regs -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(_),
+		VarInfo = VarInfo0
+	;
+		VarInfo0 = var_locn_info(VarLocnInfo0),
+		var_locn__unlock_regs(VarLocnInfo0, VarLocnInfo),
+		VarInfo = var_locn_info(VarLocnInfo)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
+:- pred code_info__get_eager_var_locns_info(var_locn_info::out,
+	code_info::in, code_info::out) is det.
+
+code_info__get_eager_var_locns_info(VarLocnInfo) -->
+	code_info__get_var_locns_info(VarInfo),
+	{
+		VarInfo = exprn_info(_),
+		error("lazy code_info__get_eager_var_locns_info")
+	;
+		VarInfo = var_locn_info(VarLocnInfo)
+	}.
+
+:- pred code_info__get_lazy_var_locns_info(exprn_info::out,
+	code_info::in, code_info::out) is det.
+
+code_info__get_lazy_var_locns_info(Exprn) -->
+	code_info__get_var_locns_info(VarInfo),
+	{
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo = var_locn_info(_),
+		error("eager code_info__get_lazy_var_locns_info")
+	}.
+
 	% As a sanity check, we could test whether any known variable
-	% has its only value in a reguster, but we don't.
+	% has its only value in a register, but we do so only with eager
+	% code generation.
 code_info__clear_all_registers -->
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__clobber_regs([], Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__clobber_regs([], Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__clobber_all_regs(VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
+code_info__clobber_regs(Regs) -->
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(_Exprn0),
+		% The clobber_regs predicate has no function except to ensure
+		% that sanity check in eager code generation does not fail
+		% when it shouldn't. Since lazy code generation lacks this
+		% sanity check, it doesn't need to do anything.
+		VarInfo = VarInfo0
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__clobber_regs(Regs, VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo).
+
+code_info__save_variables(OutArgs, Code) -->
+	code_info__get_known_variables(Variables0),
+	{ set__list_to_set(Variables0, Vars0) },
+	code_info__get_module_info(ModuleInfo),
+	code_info__get_pred_id(PredId),
+	{ module_info_pred_info(ModuleInfo, PredId, PredInfo) },
+	code_info__get_globals(Globals),
+	{ body_should_use_typeinfo_liveness(PredInfo, Globals,
+		TypeInfoLiveness) },
+	code_info__get_proc_info(ProcInfo),
+	{ proc_info_vartypes(ProcInfo, VarTypes) },
+	{ proc_info_typeinfo_varmap(ProcInfo, TVarMap) },
+	{ proc_info_maybe_complete_with_typeinfo_vars(Vars0, TypeInfoLiveness,
+		VarTypes, TVarMap, Vars1) },
+	{ set__difference(Vars1, OutArgs, Vars) },
+	{ set__to_sorted_list(Vars, Variables) },
+	code_info__save_variables_2(Variables, Code).
+
+:- pred code_info__save_variables_2(list(prog_var)::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+code_info__save_variables_2([], empty) --> [].
+code_info__save_variables_2([Var | Vars], Code) -->
+	code_info__save_variable_on_stack(Var, CodeA),
+	code_info__save_variables_2(Vars, CodeB),
+	{ Code = tree(CodeA, CodeB) }.
+
 code_info__save_variable_on_stack(Var, Code) -->
 	code_info__get_variable_slot(Var, Slot),
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__place_var(Var, Slot, Code, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+	code_info__get_var_locns_info(VarInfo0),
+	{
+		VarInfo0 = exprn_info(Exprn0),
+		code_exprn__place_var(Var, Slot, Code, Exprn0, Exprn),
+		VarInfo = exprn_info(Exprn)
+	;
+		VarInfo0 = var_locn_info(VarLocn0),
+		var_locn__place_var(Var, Slot, Code, VarLocn0, VarLocn),
+		VarInfo = var_locn_info(VarLocn)
+	},
+	code_info__set_var_locns_info(VarInfo).
 
 code_info__save_variables_on_stack([], empty) --> [].
 code_info__save_variables_on_stack([Var | Vars], Code) -->
@@ -3133,8 +3676,14 @@
 	{ Code = tree(FirstCode, RestCode) }.
 
 code_info__max_reg_in_use(Max) -->
-	code_info__get_exprn_info(Exprn),
-	{ code_exprn__max_reg_in_use(Exprn, Max) }.
+	code_info__get_var_locns_info(VarInfo),
+	{
+		VarInfo = exprn_info(Exprn),
+		code_exprn__max_reg_in_use(Exprn, Max)
+	;
+		VarInfo = var_locn_info(VarLocn),
+		var_locn__max_reg_in_use(VarLocn, Max)
+	}.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
Index: compiler/code_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_util.m,v
retrieving revision 1.122
diff -u -b -r1.122 code_util.m
--- compiler/code_util.m	2000/08/09 07:46:20	1.122
+++ compiler/code_util.m	2000/08/11 08:05:07
@@ -86,6 +86,9 @@
 :- pred code_util__arg_loc_to_register(arg_loc, lval).
 :- mode code_util__arg_loc_to_register(in, out) is det.
 
+:- pred code_util__max_mentioned_reg(list(lval), int).
+:- mode code_util__max_mentioned_reg(in, out) is det.
+
 	% Determine whether a goal might allocate some heap space,
 	% i.e. whether it contains any construction unifications
 	% or predicate calls.  BEWARE that this predicate is only
@@ -178,6 +181,9 @@
 :- pred code_util__lvals_in_lval(lval, list(lval)).
 :- mode code_util__lvals_in_lval(in, out) is det.
 
+:- pred code_util__lvals_in_lvals(list(lval), list(lval)).
+:- mode code_util__lvals_in_lvals(in, out) is det.
+
 %---------------------------------------------------------------------------%
 
 :- implementation.
@@ -379,6 +385,23 @@
 
 %-----------------------------------------------------------------------------%
 
+code_util__max_mentioned_reg(Lvals, MaxRegNum) :-
+	code_util__max_mentioned_reg_2(Lvals, 0, MaxRegNum).
+
+:- pred code_util__max_mentioned_reg_2(list(lval)::in, int::in, int::out)
+	is det.
+
+code_util__max_mentioned_reg_2([], MaxRegNum, MaxRegNum).
+code_util__max_mentioned_reg_2([Lval | Lvals], MaxRegNum0, MaxRegNum) :-
+	( Lval = reg(r, N) ->
+		int__max(MaxRegNum0, N, MaxRegNum1)
+	;
+		MaxRegNum1 = MaxRegNum0
+	),
+	code_util__max_mentioned_reg_2(Lvals, MaxRegNum1, MaxRegNum).
+
+%-----------------------------------------------------------------------------%
+
 code_util__predinfo_is_builtin(PredInfo) :-
 	pred_info_module(PredInfo, ModuleName),
 	pred_info_name(PredInfo, PredName),
@@ -769,6 +792,12 @@
 	).
 
 %-----------------------------------------------------------------------------%
+
+code_util__lvals_in_lvals([], []).
+code_util__lvals_in_lvals([First | Rest], Lvals) :-
+	code_util__lvals_in_lval(First, FirstLvals),
+	code_util__lvals_in_lvals(Rest, RestLvals),
+	list__append(FirstLvals, RestLvals, Lvals).
 
 code_util__lvals_in_rval(lval(Lval), [Lval | Lvals]) :-
 	code_util__lvals_in_lval(Lval, Lvals).
Index: compiler/continuation_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/continuation_info.m,v
retrieving revision 1.33
diff -u -b -r1.33 continuation_info.m
--- compiler/continuation_info.m	2000/08/21 09:42:00	1.33
+++ compiler/continuation_info.m	2000/08/23 03:36:29
@@ -272,13 +272,13 @@
 	% of a call.
 :- pred continuation_info__generate_return_live_lvalues(
 	assoc_list(prog_var, arg_loc)::in, instmap::in, list(prog_var)::in,
-	map(prog_var, set(rval))::in, assoc_list(lval, slot_contents)::in,
+	map(prog_var, set(lval))::in, assoc_list(lval, slot_contents)::in,
 	proc_info::in, module_info::in, globals::in, list(liveinfo)::out)
 	is det.
 
 	% Generate the layout information we need for a resumption point,
 	% a label where forward execution can restart after backtracking.
-:- pred continuation_info__generate_resume_layout(map(prog_var, set(rval))::in,
+:- pred continuation_info__generate_resume_layout(map(prog_var, set(lval))::in,
 	assoc_list(lval, slot_contents)::in, instmap::in, proc_info::in,
 	module_info::in, layout_label_info::out) is det.
 
@@ -289,7 +289,7 @@
 	% For each type variable in the given list, find out where the
 	% typeinfo var for that type variable is.
 :- pred continuation_info__find_typeinfos_for_tvars(list(tvar)::in,
-	map(prog_var, set(rval))::in, proc_info::in,
+	map(prog_var, set(lval))::in, proc_info::in,
 	map(tvar, set(layout_locn))::out) is det.
 
 %-----------------------------------------------------------------------------%
@@ -525,7 +525,7 @@
 
 :- pred continuation_info__generate_var_live_lvalues(
 	assoc_list(prog_var, lval)::in, instmap::in,
-	map(prog_var, set(rval))::in, proc_info::in, module_info::in,
+	map(prog_var, set(lval))::in, proc_info::in, module_info::in,
 	bool::in, list(liveinfo)::out) is det.
 
 continuation_info__generate_var_live_lvalues([], _, _, _, _, _, []).
@@ -563,37 +563,32 @@
 	Layout = layout_label_info(AllInfoSet, TVarInfoMap).
 
 :- pred continuation_info__generate_resume_layout_for_vars(
-	assoc_list(prog_var, set(rval))::in, instmap::in, proc_info::in,
+	assoc_list(prog_var, set(lval))::in, instmap::in, proc_info::in,
 	module_info::in, list(var_info)::out, set(tvar)::in,
 	set(tvar)::out) is det.
 
 continuation_info__generate_resume_layout_for_vars([], _, _, _, [],
 		TVars, TVars).
-continuation_info__generate_resume_layout_for_vars([Var - RvalSet | VarRvals],
+continuation_info__generate_resume_layout_for_vars([Var - LvalSet | VarLvals],
 		InstMap, ProcInfo, ModuleInfo, [VarInfo | VarInfos],
 		TVars0, TVars) :-
-	continuation_info__generate_resume_layout_for_var(Var, RvalSet,
+	continuation_info__generate_resume_layout_for_var(Var, LvalSet,
 		InstMap, ProcInfo, ModuleInfo, VarInfo, TypeVars),
 	set__insert_list(TVars0, TypeVars, TVars1),
-	continuation_info__generate_resume_layout_for_vars(VarRvals,
+	continuation_info__generate_resume_layout_for_vars(VarLvals,
 		InstMap, ProcInfo, ModuleInfo, VarInfos, TVars1, TVars).
 
 :- pred continuation_info__generate_resume_layout_for_var(prog_var::in,
-	set(rval)::in, instmap::in, proc_info::in, module_info::in,
+	set(lval)::in, instmap::in, proc_info::in, module_info::in,
 	var_info::out, list(tvar)::out) is det.
 
-continuation_info__generate_resume_layout_for_var(Var, RvalSet, InstMap,
+continuation_info__generate_resume_layout_for_var(Var, LvalSet, InstMap,
 		ProcInfo, ModuleInfo, VarInfo, TypeVars) :-
-	set__to_sorted_list(RvalSet, RvalList),
-	( RvalList = [RvalPrime] ->
-		Rval = RvalPrime
-	;
-		error("var has more than one rval in stack resume map")
-	),
-	( Rval = lval(LvalPrime) ->
+	set__to_sorted_list(LvalSet, LvalList),
+	( LvalList = [LvalPrime] ->
 		Lval = LvalPrime
 	;
-		error("var rval is not lval in stack resume map")
+		error("var has more than one lval in stack resume map")
 	),
 	continuation_info__generate_layout_for_var(Var, InstMap, ProcInfo,
 		ModuleInfo, LiveValueType, TypeVars),
@@ -662,8 +657,8 @@
 
 :- pred continuation_info__build_closure_info(list(prog_var)::in,
 	list(type)::in, list(arg_info)::in,  list(closure_arg_info)::out,
-	instmap::in, map(prog_var, set(rval))::in,
-	map(prog_var, set(rval))::out, set(tvar)::in, set(tvar)::out)
+	instmap::in, map(prog_var, set(lval))::in,
+	map(prog_var, set(lval))::out, set(tvar)::in, set(tvar)::out)
 	is semidet.
 
 continuation_info__build_closure_info([], [], [], [], _, VarLocs, VarLocs,
@@ -674,7 +669,7 @@
 	ArgInfo = arg_info(ArgLoc, _ArgMode),
 	instmap__lookup_var(InstMap, Var, Inst),
 	Layout = closure_arg_info(Type, Inst),
-	set__singleton_set(Locations, lval(reg(r, ArgLoc))),
+	set__singleton_set(Locations, reg(r, ArgLoc)),
 	map__det_insert(VarLocs0, Var, Locations, VarLocs1),
 	type_util__real_vars(Type, VarTypeVars),
 	set__insert_list(TypeVars0, VarTypeVars, TypeVars1),
@@ -691,11 +686,10 @@
 	FindLocn = lambda([TypeInfoLocn::in, Locns::out] is det, (
 		type_info_locn_var(TypeInfoLocn, TypeInfoVar),
 		(
-			map__search(VarLocs, TypeInfoVar, TypeInfoRvalSet)
+			map__search(VarLocs, TypeInfoVar, TypeInfoLvalSet)
 		->
-			ConvertRval = lambda([Locn::out] is nondet, (
-				set__member(Rval, TypeInfoRvalSet),
-				Rval = lval(Lval),
+			ConvertLval = lambda([Locn::out] is nondet, (
+				set__member(Lval, TypeInfoLvalSet),
 				(
 					TypeInfoLocn = typeclass_info(_,
 						FieldNum),
@@ -705,7 +699,7 @@
 					Locn = direct(Lval)
 				)
 			)),
-			solutions_set(ConvertRval, Locns)
+			solutions_set(ConvertLval, Locns)
 		;
 			varset__lookup_name(VarSet, TypeInfoVar,
 				VarString),
Index: compiler/disj_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/disj_gen.m,v
retrieving revision 1.70
diff -u -b -r1.70 disj_gen.m
--- compiler/disj_gen.m	2000/03/20 05:24:47	1.70
+++ compiler/disj_gen.m	2000/07/30 14:41:53
@@ -248,6 +248,15 @@
 			code_info__reset_resume_known(BranchStart)
 		),
 
+			% Forget the variables that are needed only at the
+			% resumption point at the start of the next disjunct,
+			% so that we don't generate exceptions when their
+			% storage is clobbered by the movement of the live
+			% variables to the places indicated in the store map.
+		code_info__pop_resume_point,
+		code_info__pickup_zombies(Zombies),
+		code_info__make_vars_forward_dead(Zombies),
+
 			% Put every variable whose value is needed after
 			% the disjunction to the place indicated by StoreMap,
 			% and accumulate information about the code_info state
Index: compiler/exprn_aux.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/exprn_aux.m,v
retrieving revision 1.39
diff -u -b -r1.39 exprn_aux.m
--- compiler/exprn_aux.m	2000/04/14 08:37:48	1.39
+++ compiler/exprn_aux.m	2000/07/17 06:04:51
@@ -45,6 +45,9 @@
 :- mode exprn_aux__args_contain_rval(in, in) is semidet.
 :- mode exprn_aux__args_contain_rval(in, out) is nondet.
 
+:- pred exprn_aux__substitute_lval_in_lval(lval, lval, lval, lval).
+:- mode exprn_aux__substitute_lval_in_lval(in, in, in, out) is det.
+
 :- pred exprn_aux__substitute_lval_in_rval(lval, lval, rval, rval).
 :- mode exprn_aux__substitute_lval_in_rval(in, in, in, out) is det.
 
@@ -88,6 +91,10 @@
 	list(code_addr), list(data_addr)).
 :- mode exprn_aux__maybe_rval_list_addrs(in, out, out) is det.
 
+:- func exprn_aux__var_lval_to_rval(prog_var, lval) = rval.
+
+:- func exprn_aux__lval_to_rval(lval) = rval.
+
 %------------------------------------------------------------------------------%
 %------------------------------------------------------------------------------%
 
@@ -427,9 +434,6 @@
 		MemRef = heap_ref(Rval, Tag, N)
 	).
 
-:- pred exprn_aux__substitute_lval_in_lval(lval, lval, lval, lval).
-:- mode exprn_aux__substitute_lval_in_lval(in, in, in, out) is det.
-
 exprn_aux__substitute_lval_in_lval(OldLval, NewLval, Lval0, Lval) :-
 	(
 		Lval0 = OldLval
@@ -933,6 +937,10 @@
 		exprn_aux__maybe_rval_list_addrs(MaybeRvals,
 			CodeAddrs, DataAddrs)
 	).
+
+exprn_aux__var_lval_to_rval(_, Lval) = lval(Lval).
+
+exprn_aux__lval_to_rval(Lval) = lval(Lval).
 
 %------------------------------------------------------------------------------%
 %------------------------------------------------------------------------------%
Index: compiler/follow_vars.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/follow_vars.m,v
retrieving revision 1.56
diff -u -b -r1.56 follow_vars.m
--- compiler/follow_vars.m	2000/08/09 07:46:31	1.56
+++ compiler/follow_vars.m	2000/08/11 08:06:04
@@ -4,8 +4,7 @@
 % Public License - see the file COPYING in the Mercury distribution.
 %-----------------------------------------------------------------------------%
 
-% Main author: conway.
-% Major modification by zs.
+% Main authors: conway, zs.
 
 % This module traverses the goal for every procedure, filling in the
 % follow_vars fields of some goals. These fields constitute an advisory
@@ -32,101 +31,114 @@
 :- import_module hlds_module, hlds_pred, hlds_goal, prog_data.
 :- import_module map.
 
-:- pred find_final_follow_vars(proc_info, follow_vars).
-:- mode find_final_follow_vars(in, out) is det.
+:- pred find_final_follow_vars(proc_info::in, follow_vars_map::out, int::out)
+	is det.
 
-:- pred find_follow_vars_in_goal(hlds_goal, map(prog_var, type), module_info,
-				follow_vars, hlds_goal, follow_vars).
-:- mode find_follow_vars_in_goal(in, in, in, in, out, out) is det.
+:- pred find_follow_vars_in_goal(hlds_goal::in, map(prog_var, type)::in,
+	module_info::in, follow_vars_map::in, int::in,
+	hlds_goal::out, follow_vars_map::out, int::out) is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- implementation.
 
-:- import_module hlds_data, llds, mode_util, prog_data.
+:- import_module hlds_data, llds, mode_util, prog_data, call_gen.
 :- import_module code_util, quantification, arg_info, globals.
-:- import_module bool, list, map, set, std_util, require.
+:- import_module bool, int, list, assoc_list, map, set, std_util, require.
 
 %-----------------------------------------------------------------------------%
 
-find_final_follow_vars(ProcInfo, Follow) :-
+find_final_follow_vars(ProcInfo, FollowVarsMap, NextNonReserved) :-
 	proc_info_arg_info(ProcInfo, ArgInfo),
 	proc_info_headvars(ProcInfo, HeadVars),
-	map__init(Follow0),
-	( find_final_follow_vars_2(ArgInfo, HeadVars, Follow0, Follow1) ->
-		Follow = Follow1
-	;
-		error("find_final_follow_vars: failed")
-	).
-
-:- pred find_final_follow_vars_2(list(arg_info), list(prog_var),
-						follow_vars, follow_vars).
-:- mode find_final_follow_vars_2(in, in, in, out) is semidet.
-
-find_final_follow_vars_2([], [], Follow, Follow).
-find_final_follow_vars_2([arg_info(Loc, Mode) | Args], [Var | Vars],
-							Follow0, Follow) :-
+	assoc_list__from_corresponding_lists(ArgInfo, HeadVars,
+		ArgInfoHeadVars),
+	map__init(FollowVarsMap0),
+	find_final_follow_vars_2(ArgInfoHeadVars, FollowVarsMap0, 1,
+		FollowVarsMap, NextNonReserved).
+
+:- pred find_final_follow_vars_2(assoc_list(arg_info, prog_var)::in,
+	follow_vars_map::in, int::in, follow_vars_map::out, int::out) is det.
+
+find_final_follow_vars_2([], FollowMap, NextNonReserved,
+		FollowMap, NextNonReserved).
+find_final_follow_vars_2([arg_info(Loc, Mode) - Var | ArgInfoVars],
+		FollowVarsMap0, NextNonReserved0,
+		FollowVarsMap, NextNonReserved) :-
 	code_util__arg_loc_to_register(Loc, Reg),
-	(
-		Mode = top_out
-	->
-		map__det_insert(Follow0, Var, Reg, Follow1)
+	( Mode = top_out ->
+		map__det_insert(FollowVarsMap0, Var, Reg, FollowVarsMap1),
+		int__max(NextNonReserved0, Loc + 1, NextNonReserved1)
 	;
-		Follow0 = Follow1
+		FollowVarsMap0 = FollowVarsMap1,
+		NextNonReserved1 = NextNonReserved0
 	),
-	find_final_follow_vars_2(Args, Vars, Follow1, Follow).
+	find_final_follow_vars_2(ArgInfoVars, FollowVarsMap1, NextNonReserved1,
+		FollowVarsMap, NextNonReserved).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
-find_follow_vars_in_goal(Goal0 - GoalInfo, VarTypes, ModuleInfo, FollowVars0,
-					Goal - GoalInfo, FollowVars) :-
-	find_follow_vars_in_goal_2(Goal0, VarTypes, ModuleInfo, FollowVars0,
-					Goal, FollowVars).
+find_follow_vars_in_goal(Goal0 - GoalInfo, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Goal - GoalInfo, FollowVarsMap, NextNonReserved) :-
+	find_follow_vars_in_goal_expr(Goal0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Goal, FollowVarsMap, NextNonReserved).
 
 %-----------------------------------------------------------------------------%
 
-:- pred find_follow_vars_in_goal_2(hlds_goal_expr, map(prog_var, type),
-		module_info, follow_vars, hlds_goal_expr, follow_vars).
-:- mode find_follow_vars_in_goal_2(in, in, in, in, out, out) is det.
+:- pred find_follow_vars_in_goal_expr(hlds_goal_expr::in,
+	map(prog_var, type)::in, module_info::in, follow_vars_map::in, int::in,
+	hlds_goal_expr::out, follow_vars_map::out, int::out) is det.
 
-find_follow_vars_in_goal_2(conj(Goals0), VarTypes, ModuleInfo, FollowVars0,
-		conj(Goals), FollowVars) :-
-	find_follow_vars_in_conj(Goals0, VarTypes, ModuleInfo, FollowVars0,
-		no, Goals, FollowVars).
+find_follow_vars_in_goal_expr(conj(Goals0), VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		conj(Goals), FollowVarsMap, NextNonReserved) :-
+	find_follow_vars_in_conj(Goals0, VarTypes, ModuleInfo,
+		no, FollowVarsMap0, NextNonReserved0,
+		Goals, FollowVarsMap, NextNonReserved).
 
-find_follow_vars_in_goal_2(par_conj(Goals0, SM), VarTypes, ModuleInfo,
-		FollowVars0, par_conj(Goals, SM), FollowVars) :-
+find_follow_vars_in_goal_expr(par_conj(Goals0, SM), VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		par_conj(Goals, SM), FollowVarsMap, NextNonReserved) :-
 		% find_follow_vars_in_disj treats its list of goals as a
 		% series of independent goals, so we can use it to process
 		% independent parallel conjunction.
-	find_follow_vars_in_disj(Goals0, VarTypes, ModuleInfo, FollowVars0,
-		Goals, FollowVars).
+	find_follow_vars_in_disj(Goals0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Goals, FollowVarsMap, NextNonReserved).
 
 	% We record that at the end of each disjunct, live variables should
 	% be in the locations given by the initial follow_vars, which reflects
 	% the requirements of the code following the disjunction.
 
-find_follow_vars_in_goal_2(disj(Goals0, _), VarTypes, ModuleInfo, FollowVars0,
-		disj(Goals, FollowVars0), FollowVars) :-
-	find_follow_vars_in_disj(Goals0, VarTypes, ModuleInfo, FollowVars0,
-		Goals, FollowVars).
-
-find_follow_vars_in_goal_2(not(Goal0), VarTypes, ModuleInfo, FollowVars0,
-		not(Goal), FollowVars) :-
-	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo, FollowVars0,
-		Goal, FollowVars).
+find_follow_vars_in_goal_expr(disj(Goals0, _), VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		disj(Goals, FollowVarsMap0), FollowVarsMap, NextNonReserved) :-
+	find_follow_vars_in_disj(Goals0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Goals, FollowVarsMap, NextNonReserved).
+
+find_follow_vars_in_goal_expr(not(Goal0), VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		not(Goal), FollowVarsMap, NextNonReserved) :-
+	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Goal, FollowVarsMap, NextNonReserved).
 
 	% We record that at the end of each arm of the switch, live variables
 	% should be in the locations given by the initial follow_vars, which
 	% reflects the requirements of the code following the switch.
 
-find_follow_vars_in_goal_2(switch(Var, Det, Cases0, _), VarTypes, ModuleInfo,
-		FollowVars0, switch(Var, Det, Cases, FollowVars0),
-		FollowVars) :-
-	find_follow_vars_in_cases(Cases0, VarTypes, ModuleInfo, FollowVars0,
-		Cases, FollowVars).
+find_follow_vars_in_goal_expr(switch(Var, Det, Cases0, _), VarTypes,
+		ModuleInfo, FollowVarsMap0, NextNonReserved0,
+		switch(Var, Det, Cases, FollowVarsMap0),
+		FollowVarsMap, NextNonReserved) :-
+	find_follow_vars_in_cases(Cases0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Cases, FollowVarsMap, NextNonReserved).
 
 	% Set the follow_vars field for the condition, the then-part and the
 	% else-part, since in general they have requirements about where
@@ -145,111 +157,164 @@
 	% follow_vars, which reflects the requirements of the code
 	% following the if-then-else.
 
-find_follow_vars_in_goal_2(if_then_else(Vars, Cond0, Then0, Else0, _),
-		VarTypes, ModuleInfo, FollowVars0,
-		if_then_else(Vars, Cond, Then, Else, FollowVars0),
-		FollowVarsCond) :-
-	find_follow_vars_in_goal(Then0, VarTypes, ModuleInfo, FollowVars0,
-		Then1, FollowVarsThen),
+find_follow_vars_in_goal_expr(if_then_else(Vars, Cond0, Then0, Else0, _),
+		VarTypes, ModuleInfo, FollowVarsMap0, NextNonReserved0,
+		if_then_else(Vars, Cond, Then, Else, FollowVarsMap0),
+		FollowVarsMapCond, NextNonReservedCond) :-
+	find_follow_vars_in_goal(Then0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Then1, FollowVarsMapThen, NextNonReservedThen),
+	FollowVarsThen = follow_vars(FollowVarsMapThen, NextNonReservedThen),
 	goal_set_follow_vars(Then1, yes(FollowVarsThen), Then),
-	find_follow_vars_in_goal(Cond0, VarTypes, ModuleInfo, FollowVarsThen,
-		Cond1, FollowVarsCond),
-	goal_set_follow_vars(Cond1, yes(FollowVarsCond), Cond),
-	find_follow_vars_in_goal(Else0, VarTypes, ModuleInfo, FollowVars0,
-		Else1, FollowVarsElse),
-	goal_set_follow_vars(Else1, yes(FollowVarsElse), Else).
 
-find_follow_vars_in_goal_2(some(Vars, CanRemove, Goal0), VarTypes, ModuleInfo,
-		FollowVars0, some(Vars, CanRemove, Goal), FollowVars) :-
-	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo, FollowVars0,
-		Goal, FollowVars).
-
-	% XXX These follow-vars aren't correct since the desired positions for
-	% XXX the arguments are different from an ordinary call --- they are
-	% XXX as required by the builtin operation.
-find_follow_vars_in_goal_2(
-		generic_call(GenericCall, Args, Modes, Det),
-		VarTypes, ModuleInfo, _FollowVars0,
-		generic_call(GenericCall, Args, Modes, Det),
-		FollowVars) :-
-	determinism_to_code_model(Det, CodeModel),
-	map__apply_to_list(Args, VarTypes, Types),
-	make_arg_infos(Types, Modes, CodeModel, ModuleInfo, ArgInfo),
-	find_follow_vars_from_arginfo(ArgInfo, Args, FollowVars).
+	find_follow_vars_in_goal(Cond0, VarTypes, ModuleInfo,
+		FollowVarsMapThen, NextNonReservedThen,
+		Cond1, FollowVarsMapCond, NextNonReservedCond),
+	FollowVarsCond = follow_vars(FollowVarsMapCond, NextNonReservedCond),
+	goal_set_follow_vars(Cond1, yes(FollowVarsCond), Cond),
 
-find_follow_vars_in_goal_2(call(A,B,C,D,E,F), _, ModuleInfo,
-		FollowVars0, call(A,B,C,D,E,F), FollowVars) :-
-	(
-		D = inline_builtin
-	->
-		FollowVars = FollowVars0
-	;
-		find_follow_vars_in_call(A, B, C, ModuleInfo, FollowVars)
-	).
+	find_follow_vars_in_goal(Else0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Else1, FollowVarsMapElse, NextNonReservedElse),
+	FollowVarsElse = follow_vars(FollowVarsMapElse, NextNonReservedElse),
+	goal_set_follow_vars(Else1, yes(FollowVarsElse), Else).
 
-find_follow_vars_in_goal_2(unify(A,B,C,D,E), _, _ModuleInfo,
-		FollowVars0, unify(A,B,C,D,E), FollowVars) :-
+find_follow_vars_in_goal_expr(some(Vars, CanRemove, Goal0),
+		VarTypes, ModuleInfo, FollowVarsMap0, NextNonReserved0,
+		some(Vars, CanRemove, Goal), FollowVarsMap, NextNonReserved) :-
+	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Goal, FollowVarsMap, NextNonReserved).
+
+find_follow_vars_in_goal_expr(unify(A,B,C,D,E), _, _ModuleInfo,
+		FollowVarsMap0, NextNonReserved,
+		unify(A,B,C,D,E), FollowVarsMap, NextNonReserved) :-
 	(
 		D = assign(LVar, RVar),
-		map__search(FollowVars0, LVar, DesiredLoc)
+		map__search(FollowVarsMap0, LVar, DesiredLoc)
 	->
-		map__set(FollowVars0, RVar, DesiredLoc, FollowVars)
+		map__set(FollowVarsMap0, RVar, DesiredLoc, FollowVarsMap)
 	;
-		FollowVars = FollowVars0
+		FollowVarsMap = FollowVarsMap0
 	).
 
-find_follow_vars_in_goal_2(pragma_foreign_code(A,B,C,D,E,F,G,H), 
-		_, _ModuleInfo, FollowVars,
-		pragma_foreign_code(A,B,C,D,E,F,G,H), FollowVars).
+find_follow_vars_in_goal_expr(pragma_foreign_code(A,B,C,D,E,F,G,H),
+		_, _ModuleInfo, FollowVarsMap, NextNonReserved,
+		pragma_foreign_code(A,B,C,D,E,F,G,H),
+		FollowVarsMap, NextNonReserved).
 
-find_follow_vars_in_goal_2(bi_implication(_,_), _, _, _, _, _) :-
+find_follow_vars_in_goal_expr(bi_implication(_,_), _, _, _, _, _, _, _) :-
 	% these should have been expanded out by now
 	error("find_follow_vars_in_goal_2: unexpected bi_implication").
 
+find_follow_vars_in_goal_expr(
+		generic_call(GenericCall, Args, Modes, Det),
+		VarTypes, ModuleInfo, _FollowVarsMap0, _NextNonReserved0,
+		generic_call(GenericCall, Args, Modes, Det),
+		FollowVarsMap, NextNonReserved) :-
+	determinism_to_code_model(Det, CodeModel),
+	map__apply_to_list(Args, VarTypes, Types),
+	call_gen__maybe_remove_aditi_state_args(GenericCall,
+		Args, Types, Modes, EffArgs, EffTypes, EffModes),
+	make_arg_infos(EffTypes, EffModes, CodeModel, ModuleInfo, EffArgInfo),
+	assoc_list__from_corresponding_lists(EffArgs, EffArgInfo,
+		EffArgsInfos),
+	call_gen__partition_args(EffArgsInfos, EffInVars, _),
+	call_gen__generic_call_info(CodeModel, GenericCall, _,
+		SpecifierArgInfos, FirstInput),
+	map__init(FollowVarsMap0),
+	find_follow_vars_from_arginfo(SpecifierArgInfos, FollowVarsMap0, 1,
+		FollowVarsMap1, _),
+	find_follow_vars_from_sequence(EffInVars, FirstInput, FollowVarsMap1,
+		FollowVarsMap, NextNonReserved).
+
+find_follow_vars_in_goal_expr(call(PredId, ProcId, Args, State, E,F),
+		_, ModuleInfo, FollowVarsMap0, NextNonReserved0,
+		call(PredId, ProcId, Args, State, E,F),
+		FollowVarsMap, NextNonReserved) :-
+	( State = inline_builtin ->
+		FollowVarsMap = FollowVarsMap0,
+		NextNonReserved = NextNonReserved0
+	;
+		find_follow_vars_in_call(PredId, ProcId, Args, ModuleInfo,
+			FollowVarsMap, NextNonReserved)
+	).
+
 %-----------------------------------------------------------------------------%
 
-:- pred find_follow_vars_in_call(pred_id, proc_id, list(prog_var), module_info,
-						follow_vars).
-:- mode find_follow_vars_in_call(in, in, in, in, out) is det.
+:- pred find_follow_vars_in_call(pred_id::in, proc_id::in, list(prog_var)::in,
+	module_info::in, follow_vars_map::out, int::out) is det.
 
-find_follow_vars_in_call(PredId, ProcId, Args, ModuleInfo, Follow) :-
+find_follow_vars_in_call(PredId, ProcId, Args, ModuleInfo,
+		FollowVarsMap, NextNonReserved) :-
 	module_info_preds(ModuleInfo, PredTable),
 	map__lookup(PredTable, PredId, PredInfo),
 	pred_info_procedures(PredInfo, ProcTable),
 	map__lookup(ProcTable, ProcId, ProcInfo),
 	proc_info_arg_info(ProcInfo, ArgInfo),
-	find_follow_vars_from_arginfo(ArgInfo, Args, Follow).
+	assoc_list__from_corresponding_lists(Args, ArgInfo, ArgsInfos),
+	map__init(FollowVarsMap0),
+	find_follow_vars_from_arginfo(ArgsInfos, FollowVarsMap0, 1,
+		FollowVarsMap, NextNonReserved).
+
+:- pred find_follow_vars_from_arginfo(assoc_list(prog_var, arg_info)::in,
+	follow_vars_map::in, int::in, follow_vars_map::out, int::out) is det.
+
+find_follow_vars_from_arginfo([], FollowVarsMap, NextNonReserved,
+		FollowVarsMap, NextNonReserved).
+find_follow_vars_from_arginfo([ArgVar - arg_info(Loc, Mode) | ArgsInfos],
+		FollowVarsMap0, NextNonReserved0,
+		FollowVarsMap, NextNonReserved) :-
+	code_util__arg_loc_to_register(Loc, Lval),
+	( Mode = top_in ->
+		( map__insert(FollowVarsMap0, ArgVar, Lval, FollowVarsMap1) ->
+			FollowVarsMap2 = FollowVarsMap1
+		;
+			% The call is not in superhomogeneous form: this
+			% argument has appeared before. Since the earlier
+			% appearance will have given the variable a smaller
+			% register number, we prefer that location to the one
+			% we would give to this appearance of the variable.
+			FollowVarsMap2 = FollowVarsMap0
+		),
+		( Lval = reg(r, RegNum) ->
+			int__max(NextNonReserved0, RegNum + 1,
+				NextNonReserved1)
+		;
+			error("arg_info puts arg in non-reg lval")
+		)
+	;
+		FollowVarsMap2 = FollowVarsMap0,
+		NextNonReserved1 = NextNonReserved0
+	),
+	find_follow_vars_from_arginfo(ArgsInfos,
+		FollowVarsMap2, NextNonReserved1,
+		FollowVarsMap, NextNonReserved).
 
-:- pred find_follow_vars_from_arginfo(list(arg_info), list(prog_var),
-		follow_vars).
-:- mode find_follow_vars_from_arginfo(in, in, out) is det.
+%-----------------------------------------------------------------------------%
 
-find_follow_vars_from_arginfo(ArgInfo, Args, Follow) :-
-	map__init(Follow0),
-	(
-		find_follow_vars_from_arginfo_2(ArgInfo, Args, Follow0, Follow1)
-	->
-		Follow = Follow1
-	;
-		error("find_follow_vars_from_arginfo: failed")
-	).
+:- pred find_follow_vars_from_sequence(list(prog_var)::in, int::in,
+	follow_vars_map::in, follow_vars_map::out, int::out) is det.
 
-:- pred find_follow_vars_from_arginfo_2(list(arg_info), list(prog_var),
-						follow_vars, follow_vars).
-:- mode find_follow_vars_from_arginfo_2(in, in, in, out) is semidet.
-
-find_follow_vars_from_arginfo_2([], [], Follow, Follow).
-find_follow_vars_from_arginfo_2([arg_info(Loc, Mode) | Args], [Var | Vars],
-							Follow0, Follow) :-
-	code_util__arg_loc_to_register(Loc, Reg),
+find_follow_vars_from_sequence([], NextRegNum, FollowVarsMap,
+		FollowVarsMap, NextRegNum).
+find_follow_vars_from_sequence([InVar | InVars], NextRegNum, FollowVarsMap0,
+		FollowVarsMap, NextNonReserved) :-
 	(
-		Mode = top_in
+		map__insert(FollowVarsMap0, InVar, reg(r, NextRegNum),
+			FollowVarsMap1)
 	->
-		map__set(Follow0, Var, Reg, Follow1)
+		FollowVarsMap2 = FollowVarsMap1
 	;
-		Follow0 = Follow1
+		% The call is not in superhomogeneous form: this argument has
+		% appeared before. Since the earlier appearance will have given
+		% the variable a smaller register number, we prefer that
+		% location to the one we would give to this appearance of the
+		% variable.
+		FollowVarsMap2 = FollowVarsMap0
 	),
-	find_follow_vars_from_arginfo_2(Args, Vars, Follow1, Follow).
+	find_follow_vars_from_sequence(InVars, NextRegNum + 1, FollowVarsMap2,
+		FollowVarsMap, NextNonReserved).
 
 %-----------------------------------------------------------------------------%
 
@@ -273,19 +338,23 @@
 	%
 	% This code is used both for disjunction and parallel conjunction.
 
-:- pred find_follow_vars_in_disj(list(hlds_goal), map(prog_var, type),
-		module_info, follow_vars, list(hlds_goal), follow_vars).
-:- mode find_follow_vars_in_disj(in, in, in, in, out, out) is det.
-
-find_follow_vars_in_disj([], _, _ModuleInfo, FollowVars,
-			[], FollowVars).
-find_follow_vars_in_disj([Goal0 | Goals0], VarTypes, ModuleInfo, FollowVars0,
-						[Goal | Goals], FollowVars) :-
-	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo, FollowVars0,
-		Goal1, FollowVars),
+:- pred find_follow_vars_in_disj(list(hlds_goal)::in, map(prog_var, type)::in,
+	module_info::in, follow_vars_map::in, int::in,
+	list(hlds_goal)::out, follow_vars_map::out, int::out) is det.
+
+find_follow_vars_in_disj([], _, _ModuleInfo, FollowVarsMap, NextNonReserved,
+		[], FollowVarsMap, NextNonReserved).
+find_follow_vars_in_disj([Goal0 | Goals0], VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		[Goal | Goals], FollowVarsMap, NextNonReserved) :-
+	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Goal1, FollowVarsMap, NextNonReserved),
+	FollowVars = follow_vars(FollowVarsMap, NextNonReserved),
 	goal_set_follow_vars(Goal1, yes(FollowVars), Goal),
-	find_follow_vars_in_disj(Goals0, VarTypes, ModuleInfo, FollowVars0,
-		Goals, _FollowVars1).
+	find_follow_vars_in_disj(Goals0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Goals, _FollowVarsMap, _NextNonReserved).
 
 %-----------------------------------------------------------------------------%
 
@@ -300,32 +369,39 @@
 	% its follow_vars) and to let different branches "vote" on
 	% what should be in registers.
 
-:- pred find_follow_vars_in_cases(list(case), map(prog_var, type), module_info,
-				follow_vars, list(case), follow_vars).
-:- mode find_follow_vars_in_cases(in, in, in, in, out, out) is det.
+:- pred find_follow_vars_in_cases(list(case)::in, map(prog_var, type)::in,
+	module_info::in, follow_vars_map::in, int::in,
+	list(case)::out, follow_vars_map::out, int::out) is det.
 
-find_follow_vars_in_cases([], _, _ModuleInfo, FollowVars, [], FollowVars).
+find_follow_vars_in_cases([], _, _ModuleInfo, FollowVarsMap, NextNonReserved,
+		[], FollowVarsMap, NextNonReserved).
 find_follow_vars_in_cases([case(Cons, Goal0) | Goals0], VarTypes, ModuleInfo,
-			FollowVars0, [case(Cons, Goal) | Goals], FollowVars) :-
-	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo, FollowVars0,
-		Goal1, FollowVars),
+		FollowVarsMap0, NextNonReserved0,
+		[case(Cons, Goal) | Goals], FollowVarsMap, NextNonReserved) :-
+	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved0,
+		Goal1, FollowVarsMap, NextNonReserved),
+	FollowVars = follow_vars(FollowVarsMap, NextNonReserved),
 	goal_set_follow_vars(Goal1, yes(FollowVars), Goal),
-	find_follow_vars_in_cases(Goals0, VarTypes, ModuleInfo, FollowVars0,
-		Goals, _FollowVars1).
+	find_follow_vars_in_cases(Goals0, VarTypes, ModuleInfo,
+		FollowVarsMap0, NextNonReserved,
+		Goals, _FollowVarsMap, _NextNonReserved).
 
 %-----------------------------------------------------------------------------%
 
 	% We attach the follow_vars to each goal that follows a goal
 	% that is not cachable by the code generator.
 
-:- pred find_follow_vars_in_conj(list(hlds_goal), map(prog_var, type),
-		module_info, follow_vars, bool, list(hlds_goal), follow_vars).
-:- mode find_follow_vars_in_conj(in, in, in, in, in, out, out) is det.
-
-find_follow_vars_in_conj([], _, _ModuleInfo, FollowVars,
-		_AttachToFirst, [], FollowVars).
-find_follow_vars_in_conj([Goal0 | Goals0], VarTypes, ModuleInfo, FollowVars0,
-		AttachToFirst, [Goal | Goals], FollowVars) :-
+:- pred find_follow_vars_in_conj(list(hlds_goal)::in, map(prog_var, type)::in,
+	module_info::in, bool::in, follow_vars_map::in, int::in,
+	list(hlds_goal)::out, follow_vars_map::out, int::out) is det.
+
+find_follow_vars_in_conj([], _, _ModuleInfo, _AttachToFirst,
+		FollowVarsMap, NextNonReserved,
+		[], FollowVarsMap, NextNonReserved).
+find_follow_vars_in_conj([Goal0 | Goals0], VarTypes, ModuleInfo, AttachToFirst,
+		FollowVarsMap0, NextNonReserved0,
+		[Goal | Goals], FollowVarsMap, NextNonReserved) :-
 	(
 		Goal0 = GoalExpr0 - _,
 		(
@@ -340,12 +416,15 @@
 	;
 		AttachToNext = yes
 	),
-	find_follow_vars_in_conj(Goals0, VarTypes, ModuleInfo, FollowVars0,
-		AttachToNext, Goals, FollowVars1),
-	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo, FollowVars1,
-		Goal1, FollowVars),
+	find_follow_vars_in_conj(Goals0, VarTypes, ModuleInfo, AttachToNext,
+		FollowVarsMap0, NextNonReserved0,
+		Goals, FollowVarsMap1, NextNonReserved1),
+	find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo,
+		FollowVarsMap1, NextNonReserved1,
+		Goal1, FollowVarsMap, NextNonReserved),
 	(
 		AttachToFirst = yes,
+		FollowVars = follow_vars(FollowVarsMap, NextNonReserved),
 		goal_set_follow_vars(Goal1, yes(FollowVars), Goal)
 	;
 		AttachToFirst = no,
Index: compiler/goal_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/goal_util.m,v
retrieving revision 1.63
diff -u -b -r1.63 goal_util.m
--- compiler/goal_util.m	2000/08/09 07:46:32	1.63
+++ compiler/goal_util.m	2000/08/11 07:53:44
@@ -533,7 +533,10 @@
 		MaybeFollowVars = no
 	;
 		MaybeFollowVars0 = yes(FollowVars0),
-		goal_util__rename_var_maps(FollowVars0, Must, Subn, FollowVars),
+		FollowVars0 = follow_vars(FollowVarsMap0, NextReserved),
+		goal_util__rename_var_maps(FollowVarsMap0, Must, Subn,
+			FollowVarsMap),
+		FollowVars = follow_vars(FollowVarsMap, NextReserved),
 		MaybeFollowVars = yes(FollowVars)
 	),
 	goal_info_set_follow_vars(GoalInfo6, MaybeFollowVars, GoalInfo).
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.88
diff -u -b -r1.88 handle_options.m
--- compiler/handle_options.m	2000/01/10 05:26:18	1.88
+++ compiler/handle_options.m	2000/07/17 06:04:52
@@ -487,6 +487,17 @@
 	% we are expecting some to be missing.
 	option_implies(use_opt_files, warn_missing_opt_files, bool(no)),
 
+	% --no-lazy-code assumes that const(_) rvals are really constant,
+	% and that create(_) rvals with constant arguments can be materialized
+	% in an assignable rval without further code. For float_consts,
+	% the former is true only if either static_ground_terms or
+	% unboxed_floats is true, and the latter cannot be true without
+	% static_ground_terms.
+	option_neg_implies(lazy_code, static_ground_terms, bool(yes)),
+
+	% --no-lazy-code requires --follow-vars for acceptable performance.
+	option_neg_implies(lazy_code, follow_vars, bool(yes)),
+
 	% --optimize-frames requires --optimize-labels and --optimize-jumps
 	option_implies(optimize_frames, optimize_labels, bool(yes)),
 	option_implies(optimize_frames, optimize_jumps, bool(yes)).
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_goal.m,v
retrieving revision 1.74
diff -u -b -r1.74 hlds_goal.m
--- compiler/hlds_goal.m	2000/08/09 07:46:35	1.74
+++ compiler/hlds_goal.m	2000/08/11 07:53:44
@@ -350,11 +350,21 @@
 				% The only legal lvals in the range are
 				% stackvars and framevars.
 
-:- type follow_vars	==	map(prog_var, lval).
+:- type follow_vars_map	==	map(prog_var, lval).
+
+:- type follow_vars	--->	follow_vars(follow_vars_map, int).
 				% Advisory information about where variables
-				% ought to be put next. The legal range
-				% includes the nonexistent register r(-1),
-				% which indicates any available register.
+				% ought to be put next. Variables may or may
+				% not appear in the map. If they do, then the
+				% associated lval says where the value of that
+				% variable ought to be put when it is computed,
+				% or, if the lval refers to the nonexistent
+				% register r(-1), it says that it should be
+				% put into an available register. The integer
+				% in the second half of the pair gives the
+				% number of the first register that is
+				% not reserved for other purposes, and is
+				% free to hold such variables.
 
 :- type store_map	==	map(prog_var, lval).
 				% Authoritative information about where
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.241
diff -u -b -r1.241 hlds_out.m
--- compiler/hlds_out.m	2000/08/09 07:46:39	1.241
+++ compiler/hlds_out.m	2000/08/11 07:53:44
@@ -1065,9 +1065,12 @@
 		(
 			{ MaybeFollowVars = yes(FollowVars) }
 		->
-			{ map__to_assoc_list(FollowVars, FVlist) },
+			{ FollowVars = follow_vars(FollowVarsMap, NextReg) },
+			{ map__to_assoc_list(FollowVarsMap, FVlist) },
 			hlds_out__write_indent(Indent),
-			io__write_string("% follow vars:\n"),
+			io__write_string("% follow vars: "),
+			io__write_int(NextReg),
+			io__write_string("\n"),
 			hlds_out__write_var_to_lvals(FVlist,
 				VarSet, AppendVarnums, Indent)
 		;
Index: compiler/liveness.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/liveness.m,v
retrieving revision 1.108
diff -u -b -r1.108 liveness.m
--- compiler/liveness.m	2000/08/09 07:46:51	1.108
+++ compiler/liveness.m	2000/08/11 07:53:46
@@ -58,7 +58,7 @@
 % slightly differently.  The runtime system needs access to the
 % typeinfo variables of any variable that is live at a continuation.
 % 
-% Hence, the invariant needed for alternate liveness calculation:
+% Hence, the invariant needed for typeinfo-liveness calculation:
 % 	a variable holding a typeinfo must be live at any continuation
 % 	where any variable whose type is described (in whole or in part)
 % 	by that typeinfo is live.
@@ -464,7 +464,7 @@
 detect_deadness_in_goal_2(par_conj(Goals0, SM), GoalInfo, Deadness0, LiveInfo,
 		Deadness, par_conj(Goals, SM)) :-
 	set__init(Union0),
-	goal_info_get_code_gen_nonlocals(GoalInfo, NonLocals),
+	liveness__get_nonlocals_and_typeinfos(LiveInfo, GoalInfo, NonLocals),
 	detect_deadness_in_par_conj(Goals0, Deadness0, NonLocals,
 		LiveInfo, Union0, Union, Goals),
 	set__union(Union, Deadness0, Deadness).
@@ -1109,8 +1109,9 @@
 		ValueVars1, ValueVars).
 
 %-----------------------------------------------------------------------------%
+
 
-	% Get the nonlocals, and, if doing alternate liveness, add the
+	% Get the nonlocals, and, if doing typeinfo liveness, add the
 	% typeinfo vars for the nonlocals.
 
 :- pred liveness__get_nonlocals_and_typeinfos(live_info::in, hlds_goal_info::in,
Index: compiler/lookup_switch.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/lookup_switch.m,v
retrieving revision 1.36
diff -u -b -r1.36 lookup_switch.m
--- compiler/lookup_switch.m	2000/01/14 01:10:30	1.36
+++ compiler/lookup_switch.m	2000/07/17 06:04:54
@@ -48,21 +48,18 @@
 
 :- type rval_map == map(prog_var, list(pair(int, rval))).
 
-:- pred lookup_switch__is_lookup_switch(prog_var, cases_list, hlds_goal_info,
-		can_fail, int, code_model, int, int, can_fail, can_fail,
-		list(prog_var), case_consts, maybe(set(prog_var)),
-		code_info, code_info).
-:- mode lookup_switch__is_lookup_switch(in, in, in, in, in, in, out, out,
-		out, out, out, out, out, in, out) is semidet.
+:- pred lookup_switch__is_lookup_switch(prog_var::in, cases_list::in,
+	hlds_goal_info::in, can_fail::in, int::in, store_map::in,
+	branch_end::in, branch_end::out, code_model::in, int::out, int::out,
+	can_fail::out, can_fail::out, list(prog_var)::out, case_consts::out,
+	maybe(set(prog_var))::out, code_info::in, code_info::out) is semidet.
 
 	% Generate code for a switch using a lookup table.
 
-:- pred lookup_switch__generate(prog_var, list(prog_var), case_consts,
-		int, int, can_fail, can_fail, maybe(set(prog_var)),
-		store_map, branch_end, branch_end, code_tree,
-		code_info, code_info).
-:- mode lookup_switch__generate(in, in, in, in, in, in, in, in, in,
-		in, out, out, in, out) is det.
+:- pred lookup_switch__generate(prog_var::in, list(prog_var)::in,
+	case_consts::in, int::in, int::in, can_fail::in, can_fail::in,
+	maybe(set(prog_var))::in, store_map::in, branch_end::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
 %-----------------------------------------------------------------------------%
 
@@ -79,10 +76,11 @@
 	% We need the code_info structure to generate code for the cases to
 	% get the constants (if they exist). We can't throw it away at the
 	% end because we may have allocated some new static ground term labels.
-lookup_switch__is_lookup_switch(CaseVar, TaggedCases, GoalInfo,
-		CanFail0, ReqDensity, CodeModel, FirstVal, LastVal,
-		NeedRangeCheck, NeedBitVecTest, OutVars,
+lookup_switch__is_lookup_switch(CaseVar, TaggedCases, GoalInfo, SwitchCanFail,
+		ReqDensity, StoreMap, MaybeEnd0, MaybeEnd, CodeModel,
+		FirstVal, LastVal, NeedRangeCheck, NeedBitVecTest, OutVars,
 			CaseValues, MLiveness) -->
+
 		% Since lookup switches rely on static ground terms to
 		% work efficiently, there is no point in using a lookup
 		% switch if static-ground-terms are not enabled. Well,
@@ -118,7 +116,8 @@
 	;
 		{ NeedBitVecTest0 = can_fail }
 	),
-	( { CanFail0 = can_fail } ->
+	(
+		{ SwitchCanFail = can_fail },
 		% For semidet switches, we normally need to check that
 		% the variable is in range before we index into the jump table.
 		% However, if the range of the type is sufficiently small,
@@ -129,8 +128,10 @@
 		code_info__get_module_info(ModuleInfo),
 		{ classify_type(Type, ModuleInfo, TypeCategory) },
 		(
-			dense_switch__type_range(TypeCategory, Type, TypeRange),
-			{ dense_switch__calc_density(NumCases, TypeRange, DetDensity) },
+			dense_switch__type_range(TypeCategory, Type,
+				TypeRange),
+			{ dense_switch__calc_density(NumCases, TypeRange,
+				DetDensity) },
 			{ DetDensity > ReqDensity }
 		->
 			{ NeedRangeCheck = cannot_fail },
@@ -138,26 +139,26 @@
 			{ FirstVal = 0 },
 			{ LastVal is TypeRange - 1 }
 		;
-			{ NeedRangeCheck = CanFail0 },
+			{ NeedRangeCheck = SwitchCanFail },
 			{ NeedBitVecTest = NeedBitVecTest0 },
 			{ FirstVal = FirstCaseVal },
 			{ LastVal = LastCaseVal }
 		)
 	;
-		{ NeedRangeCheck = CanFail0 },
+		{ SwitchCanFail = cannot_fail },
+		{ NeedRangeCheck = cannot_fail },
 		{ NeedBitVecTest = NeedBitVecTest0 },
 		{ FirstVal = FirstCaseVal },
 		{ LastVal = LastCaseVal }
 	),
 	lookup_switch__figure_out_output_vars(GoalInfo, OutVars),
-	lookup_switch__generate_constants(TaggedCases, OutVars, CodeModel,
-		CaseValues, MLiveness).
+	lookup_switch__generate_constants(TaggedCases, OutVars, StoreMap,
+		MaybeEnd0, MaybeEnd, CodeModel, CaseValues, MLiveness).
 
 %---------------------------------------------------------------------------%
 
-:- pred lookup_switch__figure_out_output_vars(hlds_goal_info, list(prog_var),
-		code_info, code_info).
-:- mode lookup_switch__figure_out_output_vars(in, out, in, out) is det.
+:- pred lookup_switch__figure_out_output_vars(hlds_goal_info::in,
+	list(prog_var)::out, code_info::in, code_info::out) is det.
 
 	% Figure out which variables are bound in the switch.
 	% We do this by using the current instmap and the instmap delta in
@@ -189,36 +190,43 @@
 
 %---------------------------------------------------------------------------%
 
-:- pred lookup_switch__generate_constants(cases_list, list(prog_var),
-		code_model, case_consts, maybe(set(prog_var)),
-		code_info, code_info).
-:- mode lookup_switch__generate_constants(in, in, in, out, out,
-		in, out) is semidet.
+:- pred lookup_switch__generate_constants(cases_list::in, list(prog_var)::in,
+	store_map::in, branch_end::in, branch_end::out, code_model::in,
+	case_consts::out, maybe(set(prog_var))::out,
+	code_info::in, code_info::out) is semidet.
 
 	% To figure out if the outputs are constants, we generate code for
 	% the cases, and check to see if each of the output vars is a constant,
 	% and that no actual code was generated for the goal.
-lookup_switch__generate_constants([], _Vars, _CodeModel, [], no) --> [].
-lookup_switch__generate_constants([Case|Cases], Vars, CodeModel,
-		[CaseVal|Rest], yes(Liveness)) -->
+lookup_switch__generate_constants([], _Vars, _StoreMap, MaybeEnd, MaybeEnd,
+		_CodeModel, [], no) --> [].
+lookup_switch__generate_constants([Case | Cases], Vars, StoreMap,
+		MaybeEnd0, MaybeEnd, CodeModel,
+		[CaseVal | Rest], yes(Liveness)) -->
 	{ Case = case(_, int_constant(CaseTag), _, Goal) },
 	code_info__remember_position(BranchStart),
 	code_gen__generate_goal(CodeModel, Goal, Code),
-	code_info__get_forward_live_vars(Liveness),
 	{ tree__tree_of_lists_is_empty(Code) },
+	code_info__get_forward_live_vars(Liveness),
 	lookup_switch__get_case_rvals(Vars, CaseRvals),
 	{ CaseVal = CaseTag - CaseRvals },
+		% EndCode code may contain instructions that place Vars
+		% in the locations dictated by StoreMap, and thus does not have
+		% to be empty. (The array lookup code will put those variables
+		% in those locations directly.)
+	code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd1,
+		_EndCode),
 	code_info__reset_to_position(BranchStart),
-	lookup_switch__generate_constants(Cases, Vars, CodeModel, Rest, _).
+	lookup_switch__generate_constants(Cases, Vars, StoreMap,
+		MaybeEnd1, MaybeEnd, CodeModel, Rest, _).
 
 %---------------------------------------------------------------------------%
 
-:- pred lookup_switch__get_case_rvals(list(prog_var), list(rval),
-		code_info, code_info).
-:- mode lookup_switch__get_case_rvals(in, out, in, out) is semidet.
+:- pred lookup_switch__get_case_rvals(list(prog_var)::in, list(rval)::out,
+	code_info::in, code_info::out) is semidet.
 
 lookup_switch__get_case_rvals([], []) --> [].
-lookup_switch__get_case_rvals([Var|Vars], [Rval|Rvals]) -->
+lookup_switch__get_case_rvals([Var | Vars], [Rval | Rvals]) -->
 	code_info__produce_variable(Var, Code, Rval),
 	{ tree__tree_of_lists_is_empty(Code) },
 	code_info__get_globals(Globals),
@@ -232,11 +240,10 @@
 	% lookup_switch__rval_is_constant(Rval, ExprnOpts) is
 	% true iff Rval is a constant. This depends on the options governing
 	% nonlocal gotos, asm labels enabled, and static ground terms, etc.
-:- pred lookup_switch__rval_is_constant(rval, exprn_opts).
-:- mode lookup_switch__rval_is_constant(in, in) is semidet.
+:- pred lookup_switch__rval_is_constant(rval::in, exprn_opts::in) is semidet.
 
 	% Based on code_exprn__rval_is_constant, but differs in
-	% that it doesn't happen with respect to the expresion cache.
+	% that it doesn't happen with respect to the expression cache.
 
 lookup_switch__rval_is_constant(const(Const), ExprnOpts) :-
 	exprn_aux__const_is_constant(Const, ExprnOpts, yes).
@@ -257,11 +264,11 @@
 		lookup_switch__rvals_are_constant(Args, ExprnOpts)
 	).
 
-:- pred lookup_switch__rvals_are_constant(list(maybe(rval)), exprn_opts).
-:- mode lookup_switch__rvals_are_constant(in, in) is semidet.
+:- pred lookup_switch__rvals_are_constant(list(maybe(rval))::in,
+	exprn_opts::in) is semidet.
 
 lookup_switch__rvals_are_constant([], _).
-lookup_switch__rvals_are_constant([MRval|MRvals], ExprnOpts) :-
+lookup_switch__rvals_are_constant([MRval | MRvals], ExprnOpts) :-
 	MRval = yes(Rval),
 	lookup_switch__rval_is_constant(Rval, ExprnOpts),
 	lookup_switch__rvals_are_constant(MRvals, ExprnOpts).
@@ -270,11 +277,12 @@
 
 lookup_switch__generate(Var, OutVars, CaseValues,
 		StartVal, EndVal, NeedRangeCheck, NeedBitVecCheck,
-		MLiveness, StoreMap, MaybeEnd0, MaybeEnd, Code) -->
-		% Evaluate the variable which we are going to be switching on
+		MLiveness, StoreMap, MaybeEnd0, Code) -->
+
+		% Evaluate the variable which we are going to be switching on.
 	code_info__produce_variable(Var, VarCode, Rval),
 		% If the case values start at some number other than 0,
-		% then subtract that number to give us a zero-based index
+		% then subtract that number to give us a zero-based index.
 	{ StartVal = 0 ->
 		Index = Rval
 	;
@@ -282,7 +290,7 @@
 	},
 		% If the switch is not locally deterministic, we need to
 		% check that the value of the variable lies within the
-		% appropriate range
+		% appropriate range.
 	(
 		{ NeedRangeCheck = can_fail },
 		{ Difference is EndVal - StartVal },
@@ -314,7 +322,7 @@
 		{ MLiveness = no },
 		{ error("lookup_switch__generate: no liveness!") }
 	),
-	code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd,
+	code_info__generate_branch_end(StoreMap, MaybeEnd0, _MaybeEnd,
 		LookupCode),
 		% Assemble to code together
 	{ Comment = node([comment("lookup switch") - ""]) },
@@ -328,10 +336,9 @@
 
 %------------------------------------------------------------------------------%
 
-:- pred lookup_switch__generate_bitvec_test(rval, case_consts, int, int,
-		code_tree, code_info, code_info).
-:- mode lookup_switch__generate_bitvec_test(in, in, in, in, out,
-		in, out) is det.
+:- pred lookup_switch__generate_bitvec_test(rval::in, case_consts::in,
+	int::in, int::in, code_tree::out, code_info::in, code_info::out)
+	is det.
 
 	% The bitvector is an array of words (where we use the first
 	% 32 bits of each word). Each bit represents a tag value for
@@ -366,10 +373,9 @@
 			Word) },
 	code_info__fail_if_rval_is_false(HasBit, CheckCode).
 
+:- pred lookup_switch__get_word_bits(int::out, code_info::in, code_info::out)
+	is det.
 
-:- pred lookup_switch__get_word_bits(int, code_info, code_info).
-:- mode lookup_switch__get_word_bits(out, in, out) is det.
-
 	% Prevent cross-compilation errors by making sure that
 	% the bitvector uses a number of bits that will fit both
 	% on this machine (so that we can correctly generate it),
@@ -383,8 +389,8 @@
 	{ getopt__lookup_int_option(Options, bits_per_word, TargetWordBits) },
 	{ int__min(HostWordBits, TargetWordBits, WordBits) }.
 
-:- pred generate_bit_vec(case_consts, int, int, rval, code_info, code_info).
-:- mode generate_bit_vec(in, in, in, out, in, out) is det.
+:- pred generate_bit_vec(case_consts::in, int::in, int::in, rval::out,
+	code_info::in, code_info::out) is det.
 
 	% we generate the bitvector by iterating through the cases
 	% marking the bit for each case. (We represent the bitvector
@@ -400,12 +406,11 @@
 	{ BitVec = create(0, Args, uniform(no), must_be_static,
 		CellNo, "lookup_switch_bit_vector", Reuse) }.
 
-:- pred generate_bit_vec_2(case_consts, int, int,
-			map(int, int), map(int, int)).
-:- mode generate_bit_vec_2(in, in, in, in, out) is det.
+:- pred generate_bit_vec_2(case_consts::in, int::in, int::in,
+	map(int, int)::in, map(int, int)::out) is det.
 
 generate_bit_vec_2([], _, _, Bits, Bits).
-generate_bit_vec_2([Tag-_|Rest], Start, WordBits, Bits0, Bits) :-
+generate_bit_vec_2([Tag - _ | Rest], Start, WordBits, Bits0, Bits) :-
 	Val is Tag - Start,
 	Word is Val // WordBits,
 	Offset is Val mod WordBits,
@@ -419,16 +424,16 @@
 	map__set(Bits0, Word, X1, Bits1),
 	generate_bit_vec_2(Rest, Start, WordBits, Bits1, Bits).
 
-:- pred generate_bit_vec_args(list(pair(int)), int, list(maybe(rval))).
-:- mode generate_bit_vec_args(in, in, out) is det.
+:- pred generate_bit_vec_args(list(pair(int))::in, int::in,
+	list(maybe(rval))::out) is det.
 
 generate_bit_vec_args([], _, []).
-generate_bit_vec_args([Word - Bits|Rest], Count, [yes(Rval)|Rvals]) :-
+generate_bit_vec_args([Word - Bits | Rest], Count, [yes(Rval) | Rvals]) :-
 	(
 		Count < Word
 	->
 		WordVal = 0,
-		Remainder = [Word - Bits|Rest]
+		Remainder = [Word - Bits | Rest]
 	;
 		WordVal = Bits,
 		Remainder = Rest
@@ -439,27 +444,25 @@
 
 %------------------------------------------------------------------------------%
 
-:- pred lookup_switch__generate_terms(rval, list(prog_var),
-		case_consts, int, code_info, code_info).
-:- mode lookup_switch__generate_terms(in, in, in, in, in, out) is det.
+:- pred lookup_switch__generate_terms(rval::in, list(prog_var)::in,
+	case_consts::in, int::in, code_info::in, code_info::out) is det.
 
 	% Add an expression to the expression cache in the code_info
 	% structure for each of the output variables of the lookup
 	% switch. This is done by creating a `create' term for the
 	% array, and caching an expression for the variable to get the
-	% Index'th field of that therm.
+	% Index'th field of that term.
 
 lookup_switch__generate_terms(Index, OutVars, CaseVals, Start) -->
 	{ map__init(Empty) },
 	{ rearrange_vals(OutVars, CaseVals, Start, Empty, ValMap) },
 	lookup_switch__generate_terms_2(Index, OutVars, ValMap).
 
-:- pred lookup_switch__generate_terms_2(rval, list(prog_var),
-		rval_map, code_info, code_info).
-:- mode lookup_switch__generate_terms_2(in, in, in, in, out) is det.
+:- pred lookup_switch__generate_terms_2(rval::in, list(prog_var)::in,
+	rval_map::in, code_info::in, code_info::out) is det.
 
 lookup_switch__generate_terms_2(_Index, [], _Map) --> [].
-lookup_switch__generate_terms_2(Index, [Var|Vars], Map) -->
+lookup_switch__generate_terms_2(Index, [Var | Vars], Map) -->
 	{ map__lookup(Map, Var, Vals0) },
 	{ list__sort(Vals0, Vals) },
 	{ construct_args(Vals, 0, Args) },
@@ -467,22 +470,22 @@
 	{ Reuse = no },
 	{ ArrayTerm = create(0, Args, uniform(no), must_be_static,
 		CellNo, "lookup_switch_data", Reuse) },
-	{ LookupTerm = lval(field(yes(0), ArrayTerm, Index)) },
-	code_info__cache_expression(Var, LookupTerm),
+	{ LookupLval = field(yes(0), ArrayTerm, Index) },
+	code_info__assign_lval_to_var(Var, LookupLval),
 	lookup_switch__generate_terms_2(Index, Vars, Map).
 
-:- pred construct_args(list(pair(int, rval)), int, list(maybe(rval))).
-:- mode construct_args(in, in, out) is det.
+:- pred construct_args(list(pair(int, rval))::in, int::in,
+	list(maybe(rval))::out) is det.
 
 construct_args([], _, []).
-construct_args([Index - Rval|Rest], Count0, [yes(Arg)|Args]) :-
+construct_args([Index - Rval | Rest], Count0, [yes(Arg) | Args]) :-
 	(
 		Count0 < Index
 	->
 		% If this argument (array element) is a place-holder and
 		% will never be referenced, just fill it in with a `0'
 		Arg = const(int_const(0)),
-		Remainder = [Index - Rval|Rest]
+		Remainder = [Index - Rval | Rest]
 	;
 		Arg = Rval,
 		Remainder = Rest
@@ -492,28 +495,29 @@
 
 %------------------------------------------------------------------------------%
 
-:- pred rearrange_vals(list(prog_var), case_consts, int, rval_map, rval_map).
-:- mode rearrange_vals(in, in, in, in, out) is det.
+:- pred rearrange_vals(list(prog_var)::in, case_consts::in, int::in,
+	rval_map::in, rval_map::out) is det.
 
 	% For the purpose of constructing the terms, the case_consts
 	% structure is a bit inconvenient, so we rearrange the data
 	% into a map from var to list of tag-value pairs.
+
 rearrange_vals(_Vars, [], _Start, Map, Map).
-rearrange_vals(Vars, [Tag - Rvals|Rest], Start, Map0, Map) :-
+rearrange_vals(Vars, [Tag - Rvals | Rest], Start, Map0, Map) :-
 	assoc_list__from_corresponding_lists(Vars, Rvals, Pairs),
 	Index is Tag - Start,
 	rearrange_vals_2(Pairs, Index, Map0, Map1),
 	rearrange_vals(Vars, Rest, Start, Map1, Map).
 
-:- pred rearrange_vals_2(list(pair(prog_var, rval)), int, rval_map, rval_map).
-:- mode rearrange_vals_2(in, in, in, out) is det.
+:- pred rearrange_vals_2(list(pair(prog_var, rval))::in, int::in,
+	rval_map::in, rval_map::out) is det.
 
 rearrange_vals_2([], _, Map, Map).
-rearrange_vals_2([Var - Rval|Rest], Tag, Map0, Map) :-
+rearrange_vals_2([Var - Rval | Rest], Tag, Map0, Map) :-
 	(
 		map__search(Map0, Var, Vals0)
 	->
-		Vals = [Tag - Rval|Vals0]
+		Vals = [Tag - Rval | Vals0]
 	;
 		Vals = [Tag - Rval]
 	),
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.172
diff -u -b -r1.172 mercury_compile.m
--- compiler/mercury_compile.m	2000/08/31 03:00:18	1.172
+++ compiler/mercury_compile.m	2000/09/01 00:15:45
@@ -1237,7 +1237,7 @@
 		; hlds_pred__pred_info_is_aditi_relation(PredInfo)
 		}
 	->
-		{ ModuleInfo1 = ModuleInfo0 },
+		{ ModuleInfo3 = ModuleInfo0 },
 		{ GlobalData1 = GlobalData0 },
 		{ Code1 = [] }
 	;
@@ -1249,12 +1249,43 @@
 		;
 			[]
 		),
-		mercury_compile__backend_pass_by_preds_3(ProcIds, PredId,
-			PredInfo, ModuleInfo0, ModuleInfo1,
+		(
+			{ pred_info_module(PredInfo, PredModule) },
+			{ pred_info_name(PredInfo, PredName) },
+                        { pred_info_arity(PredInfo, PredArity) },
+                        { no_type_info_builtin(PredModule, PredName,
+				PredArity) }
+		->
+				% These predicates should never be traced,
+				% since they do not obey typeinfo_liveness.
+				% Since they may be opt_imported into other
+				% modules, we must switch off the tracing
+				% of such preds on a pred-by-pred basis.
+			{ module_info_globals(ModuleInfo0, Globals0) },
+			{ globals__get_trace_level(Globals0, TraceLevel) },
+			{ globals__set_trace_level(Globals0, none, Globals1) },
+			{ module_info_set_globals(ModuleInfo0, Globals1,
+				ModuleInfo1) },
+			{ copy(Globals1, Globals1Unique) },
+			globals__io_set_globals(Globals1Unique),
+			mercury_compile__backend_pass_by_preds_3(ProcIds,
+				PredId, PredInfo, ModuleInfo1, ModuleInfo2,
+				GlobalData0, GlobalData1, Code1),
+			{ module_info_globals(ModuleInfo2, Globals2) },
+			{ globals__set_trace_level(Globals2, TraceLevel,
+				Globals) },
+			{ module_info_set_globals(ModuleInfo2, Globals,
+				ModuleInfo3) },
+			{ copy(Globals, GlobalsUnique) },
+			globals__io_set_globals(GlobalsUnique)
+		;
+			mercury_compile__backend_pass_by_preds_3(ProcIds,
+				PredId, PredInfo, ModuleInfo0, ModuleInfo3,
 			GlobalData0, GlobalData1, Code1)
+		)
 	),
 	mercury_compile__backend_pass_by_preds_2(PredIds,
-		ModuleInfo1, ModuleInfo, GlobalData1, GlobalData, Code2),
+		ModuleInfo3, ModuleInfo, GlobalData1, GlobalData, Code2),
 	{ list__append(Code1, Code2, Code) }.
 
 :- pred mercury_compile__backend_pass_by_preds_3(list(proc_id), pred_id,
@@ -1288,7 +1319,7 @@
 
 mercury_compile__backend_pass_by_preds_4(PredInfo, ProcInfo0, ProcId, PredId,
 		ModuleInfo0, ModuleInfo, GlobalData0, GlobalData, Proc) -->
-	globals__io_get_globals(Globals),
+	{ module_info_globals(ModuleInfo0, Globals) },
 	{ globals__lookup_bool_option(Globals, follow_code, FollowCode) },
 	{ globals__lookup_bool_option(Globals, prev_code, PrevCode) },
 	( { FollowCode = yes ; PrevCode = yes } ->
@@ -1335,8 +1366,7 @@
 				PredId, ProcId, ModuleInfo3),
 	{ module_info_get_cell_counter(ModuleInfo3, CellCounter0) },
 	{ generate_proc_code(PredInfo, ProcInfo, ProcId, PredId, ModuleInfo3,
-		Globals, GlobalData0, GlobalData1, CellCounter0, CellCounter,
-		Proc0) },
+		GlobalData0, GlobalData1, CellCounter0, CellCounter, Proc0) },
 	{ globals__lookup_bool_option(Globals, optimize, Optimize) },
 	( { Optimize = yes } ->
 		optimize__proc(Proc0, GlobalData1, Proc)
Index: compiler/par_conj_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/par_conj_gen.m,v
retrieving revision 1.6
diff -u -b -r1.6 par_conj_gen.m
--- compiler/par_conj_gen.m	2000/02/10 04:47:44	1.6
+++ compiler/par_conj_gen.m	2000/08/02 02:55:57
@@ -274,7 +274,7 @@
 	code_info__get_variable_slot(Var, Slot),
 	(
 		{ map__search(VarLocations, Var, Locations) },
-		{ set__member(lval(Slot), Locations) }
+		{ set__member(Slot, Locations) }
 	->
 		[]
 	;
Index: compiler/pragma_c_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/pragma_c_gen.m,v
retrieving revision 1.36
diff -u -b -r1.36 pragma_c_gen.m
--- compiler/pragma_c_gen.m	2000/08/09 07:47:40	1.36
+++ compiler/pragma_c_gen.m	2000/08/17 10:46:45
@@ -38,7 +38,7 @@
 
 :- implementation.
 
-:- import_module hlds_module, hlds_pred, call_gen, llds_out, trace, tree.
+:- import_module hlds_module, hlds_pred, llds_out, trace, tree.
 :- import_module code_util.
 :- import_module options, globals.
 :- import_module bool, string, int, assoc_list, set, map, require, term.
@@ -350,6 +350,9 @@
 	{ pragma_select_in_args(Args, InArgs) },
 	{ pragma_select_out_args(Args, OutArgs) },
 
+	{ set__init(DeadVars0) },
+	find_dead_input_vars(InArgs, DeadVars0, DeadVars),
+
 	%
 	% Generate code to <save live variables on stack>
 	%
@@ -365,7 +368,13 @@
 		% (other than the output args) onto the stack
 		{ get_c_arg_list_vars(OutArgs, OutArgs1) },
 		{ set__list_to_set(OutArgs1, OutArgsSet) },
-		call_gen__save_variables(OutArgsSet, SaveVarsCode)
+		code_info__save_variables(OutArgsSet, SaveVarsCode)
+	),
+
+	( { CodeModel = model_semi } ->
+		code_info__reserve_r1(ReserveR1_Code)
+	;
+		{ ReserveR1_Code = empty }
 	),
 
 	%
@@ -380,13 +389,32 @@
 	% currently in r1 elsewhere, so that the C code can assign to
 	% SUCCESS_INDICATOR without clobbering anything important.
 	%
+	% With --no-lazy-code, the call to code_info__reserve_r1 will have
+	% reserved r1, ensuring that none of InArgs is placed there, and
+	% code_info__clear_r1 just releases r1. This reservation of r1
+	% is not strictly necessary, as we generate assignments from
+	% the input registers to C variables before we invoke code that could
+	% assign to SUCCESS_INDICATOR. However, by not storing an argument in
+	% r1, we don't require the C compiler to generate a copy instruction
+	% from r1 to somewhere else in cases where the last use of the variable
+	% we are trying to pass in r1 is after the first reference to
+	% SUCCESS_INDICATOR. Instead we generate that argument directly
+	% into some other location.
+	%
 	( { CodeModel = model_semi } ->
-		code_info__clear_r1(ShuffleR1_Code)
+		code_info__clear_r1(ClearR1_Code)
 	;
-		{ ShuffleR1_Code = empty }
+		{ ClearR1_Code = empty }
 	),
 
 	%
+	% We cannot kill the forward dead input arguments until we have
+	% finished generating the code producing the input variables.
+	% (The forward dead variables will be dead after the pragma_c_code,
+	% but are live during its input phase.)
+	code_info__make_vars_forward_dead(DeadVars),
+
+	%
 	% Generate <declaration of one local variable for each arg>
 	%
 	{ make_pragma_decls(Args, Decls) },
@@ -527,10 +555,11 @@
 	%
 	{ Code =
 		tree(SaveVarsCode,
+		tree(ReserveR1_Code, 
 		tree(InputVarsCode,
-		tree(ShuffleR1_Code, 
+		tree(ClearR1_Code, 
 		tree(PragmaCCode,
-		     FailureCode))))
+		     FailureCode)))))
 	}.
 
 :- pred make_proc_label_hash_define(module_info, pred_id, proc_id,
@@ -1051,6 +1080,21 @@
 
 %---------------------------------------------------------------------------%
 
+:- pred find_dead_input_vars(list(c_arg)::in, set(prog_var)::in,
+	set(prog_var)::out, code_info::in, code_info::out) is det.
+
+find_dead_input_vars([], DeadVars, DeadVars) --> [].
+find_dead_input_vars([Arg | Args], DeadVars0, DeadVars) -->
+	{ Arg = c_arg(Var, _MaybeName, _Type, _ArgInfo) },
+	( code_info__variable_is_forward_live(Var) ->
+		{ DeadVars1 = DeadVars0 }
+	;
+		{ set__insert(DeadVars0, Var, DeadVars1) }
+	),
+	find_dead_input_vars(Args, DeadVars1, DeadVars).
+
+%---------------------------------------------------------------------------%
+
 % get_pragma_input_vars returns a list of pragma_c_inputs for the pragma_c
 % data structure in the LLDS. It is essentially a list of the input variables,
 % and the corresponding rvals assigned to those (C) variables.
@@ -1061,14 +1105,14 @@
 get_pragma_input_vars([], [], empty) --> [].
 get_pragma_input_vars([Arg | Args], Inputs, Code) -->
 	{ Arg = c_arg(Var, MaybeName, Type, _ArgInfo) },
-	(
-		{ var_is_not_singleton(MaybeName, Name) }
-	->
-		code_info__produce_variable(Var, Code0, Rval),
+	( { var_is_not_singleton(MaybeName, Name) } ->
+		code_info__produce_variable(Var, FirstCode, Rval),
+		% code_info__produce_variable_in_reg(Var, FirstCode, Lval),
+		% { Rval = lval(Lval) },
 		{ Input = pragma_c_input(Name, Type, Rval) },
-		get_pragma_input_vars(Args, Inputs1, Code1),
+		get_pragma_input_vars(Args, Inputs1, RestCode),
 		{ Inputs = [Input | Inputs1] },
-		{ Code = tree(Code0, Code1) }
+		{ Code = tree(FirstCode, RestCode) }
 	;
 		% if the variable doesn't occur in the ArgNames list,
 		% it can't be used, so we just ignore it
@@ -1100,17 +1144,22 @@
 
 place_pragma_output_args_in_regs([], [], []) --> [].
 place_pragma_output_args_in_regs([Arg | Args], [Reg | Regs], Outputs) -->
+	place_pragma_output_args_in_regs(Args, Regs, Outputs0),
 	{ Arg = c_arg(Var, MaybeName, OrigType, _ArgInfo) },
 	code_info__release_reg(Reg),
+	( code_info__variable_is_forward_live(Var) ->
 	code_info__set_var_location(Var, Reg),
 	{
 		var_is_not_singleton(MaybeName, Name)
 	->
-		Outputs = [pragma_c_output(Reg, OrigType, Name) | Outputs0]
+			PragmaCOutput = pragma_c_output(Reg, OrigType, Name),
+			Outputs = [PragmaCOutput | Outputs0]
 	;
 		Outputs = Outputs0
-	},
-	place_pragma_output_args_in_regs(Args, Regs, Outputs0).
+		}
+	;
+		{ Outputs = Outputs0 }
+	).
 place_pragma_output_args_in_regs([_|_], [], _) -->
 	{ error("place_pragma_output_args_in_regs: length mismatch") }.
 place_pragma_output_args_in_regs([], [_|_], _) -->
Index: compiler/simplify.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/simplify.m,v
retrieving revision 1.81
diff -u -b -r1.81 simplify.m
--- compiler/simplify.m	2000/09/01 09:51:34	1.81
+++ compiler/simplify.m	2000/09/03 23:01:25
@@ -1808,7 +1808,7 @@
 	****/
 
 :- pred simplify__fixup_disj(list(hlds_goal), determinism, bool,
-	hlds_goal_info, follow_vars, hlds_goal_expr,
+	hlds_goal_info, store_map, hlds_goal_expr,
 	simplify_info, simplify_info).
 :- mode simplify__fixup_disj(in, in, in, in, in, out, in, out) is det.
 
@@ -1835,7 +1835,7 @@
 	%		Disjunct3
 	%	).
 
-:- pred det_disj_to_ite(list(hlds_goal), hlds_goal_info, follow_vars,
+:- pred det_disj_to_ite(list(hlds_goal), hlds_goal_info, store_map,
 	hlds_goal).
 :- mode det_disj_to_ite(in, in, in, out) is det.
 
Index: compiler/stack_layout.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/stack_layout.m,v
retrieving revision 1.48
diff -u -b -r1.48 stack_layout.m
--- compiler/stack_layout.m	2000/08/11 08:19:17	1.48
+++ compiler/stack_layout.m	2000/08/15 06:08:19
@@ -253,7 +253,7 @@
 :- implementation.
 
 :- import_module globals, options, llds_out, trace.
-:- import_module hlds_data, hlds_pred, prog_data, prog_out.
+:- import_module hlds_data, hlds_pred, prog_data, prog_util, prog_out.
 :- import_module rtti, ll_pseudo_type_info, (inst), code_util.
 :- import_module assoc_list, bool, string, int, require.
 :- import_module map, term, set.
@@ -265,7 +265,9 @@
 
 stack_layout__generate_llds(ModuleInfo0, ModuleInfo, GlobalData,
 		PossiblyDynamicLayouts, StaticLayouts, LayoutLabels) :-
-	global_data_get_all_proc_layouts(GlobalData, ProcLayoutList),
+	global_data_get_all_proc_layouts(GlobalData, ProcLayoutList0),
+	list__filter(stack_layout__valid_proc_layout, ProcLayoutList0,
+		ProcLayoutList),
 
 	module_info_name(ModuleInfo0, ModuleName),
 	module_info_get_cell_counter(ModuleInfo0, CellCounter0),
@@ -336,6 +338,19 @@
 	PossiblyDynamicLayouts = ProcLayouts,
 	stack_layout__get_cell_counter(CellCounter, LayoutInfo, _),
 	module_info_set_cell_counter(ModuleInfo0, CellCounter, ModuleInfo).
+
+:- pred stack_layout__valid_proc_layout(proc_layout_info::in) is semidet.
+
+stack_layout__valid_proc_layout(ProcLayoutInfo) :-
+	ProcLayoutInfo = proc_layout_info(EntryLabel, _Detism,
+		_StackSlots, _SuccipLoc, _MaybeCallLabel, _MaxTraceReg,
+		_TraceSlotInfo, _ForceProcIdLayout, _InternalMap),
+	code_util__extract_proc_label_from_label(EntryLabel, ProcLabel),
+	( ProcLabel = proc(_, _, DeclModule, _, _, _)
+	; ProcLabel = special_proc(_, _, DeclModule, _, _, _)
+	),
+	\+ mercury_public_builtin_module(DeclModule),
+	\+ mercury_private_builtin_module(DeclModule).
 
 %---------------------------------------------------------------------------%
 
Index: compiler/store_alloc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/store_alloc.m,v
retrieving revision 1.71
diff -u -b -r1.71 store_alloc.m
--- compiler/store_alloc.m	2000/08/09 07:47:51	1.71
+++ compiler/store_alloc.m	2000/08/11 07:53:54
@@ -57,11 +57,14 @@
 	( ApplyFollowVars = yes ->
 		proc_info_goal(ProcInfo0, Goal0),
 
-		find_final_follow_vars(ProcInfo0, FollowVars0),
+		find_final_follow_vars(ProcInfo0,
+			FollowVarsMap0, NextNonReserved0),
 		proc_info_vartypes(ProcInfo0, VarTypes),
 		find_follow_vars_in_goal(Goal0, VarTypes, ModuleInfo,
-			FollowVars0, Goal1, FollowVars),
+			FollowVarsMap0, NextNonReserved0,
+			Goal1, FollowVarsMap, NextNonReserved),
 		Goal1 = GoalExpr1 - GoalInfo1,
+		FollowVars = follow_vars(FollowVarsMap, NextNonReserved),
 		goal_info_set_follow_vars(GoalInfo1, yes(FollowVars),
 			GoalInfo2),
 		Goal2 = GoalExpr1 - GoalInfo2
@@ -110,27 +113,27 @@
 	% should not be included in the store map.
 	set__union(Liveness4, PostBirths, Liveness),
 	(
-		Goal1 = switch(Var, CanFail, Cases, FollowVars)
+		Goal1 = switch(Var, CanFail, Cases, AdvisoryStoreMap)
 	->
 		set__union(Liveness4, ResumeVars0, MappedSet),
 		set__to_sorted_list(MappedSet, MappedVars),
-		store_alloc_allocate_storage(MappedVars, FollowVars,
+		store_alloc_allocate_storage(MappedVars, AdvisoryStoreMap,
 			StackSlotInfo, StoreMap),
 		Goal = switch(Var, CanFail, Cases, StoreMap)
 	;
-		Goal1 = if_then_else(Vars, Cond, Then, Else, FollowVars)
+		Goal1 = if_then_else(Vars, Cond, Then, Else, AdvisoryStoreMap)
 	->
 		set__union(Liveness4, ResumeVars0, MappedSet),
 		set__to_sorted_list(MappedSet, MappedVars),
-		store_alloc_allocate_storage(MappedVars, FollowVars,
+		store_alloc_allocate_storage(MappedVars, AdvisoryStoreMap,
 			StackSlotInfo, StoreMap),
 		Goal = if_then_else(Vars, Cond, Then, Else, StoreMap)
 	;
-		Goal1 = disj(Disjuncts, FollowVars)
+		Goal1 = disj(Disjuncts, AdvisoryStoreMap)
 	->
 		set__union(Liveness4, ResumeVars0, MappedSet),
 		set__to_sorted_list(MappedSet, MappedVars),
-		store_alloc_allocate_storage(MappedVars, FollowVars,
+		store_alloc_allocate_storage(MappedVars, AdvisoryStoreMap,
 			StackSlotInfo, StoreMap),
 		Goal = disj(Disjuncts, StoreMap)
 	;
@@ -302,7 +305,7 @@
 	% generate a store map that maps every live variable to its own
 	% real location.
 
-:- pred store_alloc_allocate_storage(list(prog_var), follow_vars,
+:- pred store_alloc_allocate_storage(list(prog_var), store_map,
 		stack_slot_info, store_map).
 :- mode store_alloc_allocate_storage(in, in, in, out) is det.
 
Index: compiler/switch_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/switch_gen.m,v
retrieving revision 1.71
diff -u -b -r1.71 switch_gen.m
--- compiler/switch_gen.m	1999/07/13 08:53:33	1.71
+++ compiler/switch_gen.m	2000/07/26 01:57:11
@@ -100,13 +100,14 @@
 		{ globals__lookup_int_option(Globals, lookup_switch_req_density,
 			ReqDensity) },
 		lookup_switch__is_lookup_switch(CaseVar, TaggedCases, GoalInfo,
-			CanFail, ReqDensity, CodeModel, FirstVal, LastVal,
-			NeedRangeCheck, NeedBitVecCheck,
-			OutVars, CaseVals, MLiveness)
+			CanFail, ReqDensity, StoreMap, no, MaybeEndPrime,
+			CodeModel, FirstVal, LastVal, NeedRangeCheck,
+			NeedBitVecCheck, OutVars, CaseVals, MLiveness)
 	->
+		{ MaybeEnd = MaybeEndPrime },
 		lookup_switch__generate(CaseVar, OutVars, CaseVals,
 			FirstVal, LastVal, NeedRangeCheck, NeedBitVecCheck,
-			MLiveness, StoreMap, no, MaybeEnd, Code)
+			MLiveness, StoreMap, no, Code)
 	;
 		{ Indexing = yes },
 		{ SwitchCategory = atomic_switch },
Index: compiler/tag_switch.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/tag_switch.m,v
retrieving revision 1.48
diff -u -b -r1.48 tag_switch.m
--- compiler/tag_switch.m	1999/07/10 07:19:54	1.48
+++ compiler/tag_switch.m	2000/07/17 06:05:01
@@ -222,7 +222,8 @@
 	% or if the "register" we get is likely to be slower than
 	% recomputing the tag from scratch.
 
-	code_info__produce_variable_in_reg(Var, VarCode, VarRval),
+	code_info__produce_variable_in_reg(Var, VarCode, VarLval),
+	{ VarRval = lval(VarLval) },
 	code_info__acquire_reg(r, PtagReg),
 	code_info__release_reg(PtagReg),
 	{
Index: compiler/trace.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/trace.m,v
retrieving revision 1.33
diff -u -b -r1.33 trace.m
--- compiler/trace.m	2000/07/25 09:27:26	1.33
+++ compiler/trace.m	2000/08/02 02:56:13
@@ -14,7 +14,7 @@
 %
 % We reserve some slots in the stack frame of the traced procedure.
 % One contains the call sequence number, which is set in the procedure prologue
-% by incrementing a global counter. An other contains the call depth, which
+% by incrementing a global counter. Another contains the call depth, which
 % is also set by incrementing a global variable containing the depth of the
 % caller. The caller sets this global variable from its own saved depth
 % just before the call.  We also save the event number, and sometimes also
@@ -103,8 +103,8 @@
 	% of the procedure (those partially clobbered may still be of interest,
 	% although to handle them properly we need to record insts in stack
 	% layouts).
-:- pred trace__fail_vars(module_info::in, proc_info::in,
-		set(prog_var)::out) is det.
+:- pred trace__fail_vars(module_info::in, proc_info::in, set(prog_var)::out)
+	is det.
 
 	% Return the number of slots reserved for tracing information.
 	% If there are N slots, the reserved slots will be 1 through N.
@@ -691,19 +691,10 @@
 trace__produce_vars([], _, _, Tvars, Tvars, [], empty) --> [].
 trace__produce_vars([Var | Vars], VarSet, InstMap, Tvars0, Tvars,
 		[VarInfo | VarInfos], tree(VarCode, VarsCode)) -->
-	code_info__produce_variable_in_reg_or_stack(Var, VarCode, Rval),
+	code_info__produce_variable_in_reg_or_stack(Var, VarCode, Lval),
 	code_info__variable_type(Var, Type),
 	code_info__get_module_info(ModuleInfo),
 	{
-	( Rval = lval(LvalPrime) ->
-		Lval = LvalPrime
-	;
-		error("var not an lval in trace__produce_vars")
-		% If the value of the variable is known,
-		% we record it as living in a nonexistent location, r0.
-		% The code that interprets layout information must know this.
-		% Lval = reg(r, 0)
-	),
 	( varset__search_name(VarSet, Var, SearchName) ->
 		Name = SearchName
 	;
Index: compiler/unify_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/unify_gen.m,v
retrieving revision 1.107
diff -u -b -r1.107 unify_gen.m
--- compiler/unify_gen.m	2000/08/11 08:19:19	1.107
+++ compiler/unify_gen.m	2000/08/11 08:18:09
@@ -58,12 +58,20 @@
 	},
 	(
 		{ Uni = assign(Left, Right) },
+		( code_info__variable_is_forward_live(Left) ->
 		unify_gen__generate_assignment(Left, Right, Code)
 	;
+			{ Code = empty }
+		)
+	;
 		{ Uni = construct(Var, ConsId, Args, Modes, _, _, AditiInfo) },
+		( code_info__variable_is_forward_live(Var) ->
 		unify_gen__generate_construction(Var, ConsId,
 			Args, Modes, AditiInfo, Code)
 	;
+			{ Code = empty }
+		)
+	;
 		{ Uni = deconstruct(Var, ConsId, Args, Modes, _CanFail) },
 		( { CodeModel = model_det } ->
 			unify_gen__generate_det_deconstruction(Var, ConsId,
@@ -97,15 +105,13 @@
 :- mode unify_gen__generate_assignment(in, in, out, in, out) is det.
 
 unify_gen__generate_assignment(VarA, VarB, empty) -->
-	(
-		code_info__variable_is_forward_live(VarA)
-	->
-		code_info__cache_expression(VarA, var(VarB))
+	( code_info__variable_is_forward_live(VarA) ->
+		code_info__assign_var_to_var(VarA, VarB)
 	;
 		% For free-free unifications, the mode analysis reports
 		% them as assignment to the dead variable.  For such
 		% unifications we of course don't generate any code
-		{ true }
+		[]
 	).
 
 %---------------------------------------------------------------------------%
@@ -121,9 +127,9 @@
 :- mode unify_gen__generate_test(in, in, out, in, out) is det.
 
 unify_gen__generate_test(VarA, VarB, Code) -->
-	code_info__produce_variable(VarA, Code0, ValA),
-	code_info__produce_variable(VarB, Code1, ValB),
-	{ CodeA = tree(Code0, Code1) },
+	code_info__produce_variable(VarA, CodeA, ValA),
+	code_info__produce_variable(VarB, CodeB, ValB),
+	{ CodeAB = tree(CodeA, CodeB) },
 	code_info__variable_type(VarA, Type),
 	{ Type = term__functor(term__atom("string"), [], _) ->
 		Op = str_eq
@@ -133,7 +139,7 @@
 		Op = eq
 	},
 	code_info__fail_if_rval_is_false(binop(Op, ValA, ValB), FailCode),
-	{ Code = tree(CodeA, FailCode) }.
+	{ Code = tree(CodeAB, FailCode) }.
 
 %---------------------------------------------------------------------------%
 
@@ -256,9 +262,11 @@
 
 %---------------------------------------------------------------------------%
 
-	% A construction unification consists of a heap-increment to
-	% create a term, and a series of [optional] assignments to
-	% instantiate the arguments of that term.
+	% A construction unification is implemented as a simple assignment
+	% of a function symbol if the function symbol has arity zero.
+	% If the function symbol's arity is greater than zero, it is
+	% implemented as a heap-increment to create a term, and a series
+	% of [optional] assignments to instantiate the arguments of that term.
 
 :- pred unify_gen__generate_construction(prog_var, cons_id,
 		list(prog_var), list(uni_mode), maybe(rl_exprn_id),
@@ -278,17 +286,14 @@
 					in, out) is det.
 
 unify_gen__generate_construction_2(string_constant(String),
-		Var, _Args, _Modes, _, Code) -->
-	{ Code = empty },
-	code_info__cache_expression(Var, const(string_const(String))).
+		Var, _Args, _Modes, _, empty) -->
+	code_info__assign_const_to_var(Var, const(string_const(String))).
 unify_gen__generate_construction_2(int_constant(Int),
-		Var, _Args, _Modes, _, Code) -->
-	{ Code = empty },
-	code_info__cache_expression(Var, const(int_const(Int))).
+		Var, _Args, _Modes, _, empty) -->
+	code_info__assign_const_to_var(Var, const(int_const(Int))).
 unify_gen__generate_construction_2(float_constant(Float),
-		Var, _Args, _Modes, _, Code) -->
-	{ Code = empty },
-	code_info__cache_expression(Var, const(float_const(Float))).
+		Var, _Args, _Modes, _, empty) -->
+	code_info__assign_const_to_var(Var, const(float_const(Float))).
 unify_gen__generate_construction_2(no_tag, Var, Args, Modes, _, Code) -->
 	( { Args = [Arg], Modes = [Mode] } ->
 		code_info__variable_type(Arg, Type),
@@ -298,90 +303,71 @@
 		{ error(
 		"unify_gen__generate_construction_2: no_tag: arity != 1") }
 	).
-unify_gen__generate_construction_2(unshared_tag(UnsharedTag),
+unify_gen__generate_construction_2(unshared_tag(Ptag),
 		Var, Args, Modes, _, Code) -->
 	code_info__get_module_info(ModuleInfo),
-	code_info__get_next_cell_number(CellNo),
 	unify_gen__var_types(Args, ArgTypes),
 	{ unify_gen__generate_cons_args(Args, ArgTypes, Modes, ModuleInfo,
-		RVals) },
-	{ Code = empty },
+		Rvals) },
 	code_info__variable_type(Var, VarType),
 	{ unify_gen__var_type_msg(VarType, VarTypeMsg) },
-	% XXX Later we will need to worry about
-	% whether the cell must be unique or not.
-	{ Reuse = no },
-	{ Expr = create(UnsharedTag, RVals, uniform(no), can_be_either,
-		CellNo, VarTypeMsg, Reuse) },
-	code_info__cache_expression(Var, Expr).
-unify_gen__generate_construction_2(shared_remote_tag(Bits0, Num0),
+	code_info__assign_cell_to_var(Var, Ptag, Rvals, VarTypeMsg, Code).
+unify_gen__generate_construction_2(shared_remote_tag(Ptag, Sectag),
 		Var, Args, Modes, _, Code) -->
 	code_info__get_module_info(ModuleInfo),
-	code_info__get_next_cell_number(CellNo),
 	unify_gen__var_types(Args, ArgTypes),
 	{ unify_gen__generate_cons_args(Args, ArgTypes, Modes, ModuleInfo,
-		RVals0) },
+		Rvals0) },
 		% the first field holds the secondary tag
-	{ RVals = [yes(const(int_const(Num0))) | RVals0] },
-	{ Code = empty },
+	{ Rvals = [yes(const(int_const(Sectag))) | Rvals0] },
 	code_info__variable_type(Var, VarType),
 	{ unify_gen__var_type_msg(VarType, VarTypeMsg) },
-	% XXX Later we will need to worry about
-	% whether the cell must be unique or not.
-	{ Reuse = no },
-	{ Expr = create(Bits0, RVals, uniform(no), can_be_either,
-		CellNo, VarTypeMsg, Reuse) },
-	code_info__cache_expression(Var, Expr).
+	code_info__assign_cell_to_var(Var, Ptag, Rvals, VarTypeMsg, Code).
 unify_gen__generate_construction_2(shared_local_tag(Bits1, Num1),
-		Var, _Args, _Modes, _, Code) -->
-	{ Code = empty },
-	code_info__cache_expression(Var,
+		Var, _Args, _Modes, _, empty) -->
+	code_info__assign_const_to_var(Var,
 		mkword(Bits1, unop(mkbody, const(int_const(Num1))))).
 unify_gen__generate_construction_2(type_ctor_info_constant(ModuleName,
-		TypeName, TypeArity), Var, Args, _Modes, _, Code) -->
+		TypeName, TypeArity), Var, Args, _Modes, _, empty) -->
 	( { Args = [] } ->
 		[]
 	;
 		{ error("unify_gen: type-info constant has args") }
 	),
-	{ Code = empty },
 	{ RttiTypeId = rtti_type_id(ModuleName, TypeName, TypeArity) },
 	{ DataAddr = rtti_addr(RttiTypeId, type_ctor_info) },
-	code_info__cache_expression(Var, const(data_addr_const(DataAddr))).
+	code_info__assign_const_to_var(Var, const(data_addr_const(DataAddr))).
 unify_gen__generate_construction_2(base_typeclass_info_constant(ModuleName,
-		ClassId, Instance), Var, Args, _Modes, _, Code) -->
+		ClassId, Instance), Var, Args, _Modes, _, empty) -->
 	( { Args = [] } ->
 		[]
 	;
 		{ error("unify_gen: typeclass-info constant has args") }
 	),
-	{ Code = empty },
-	code_info__cache_expression(Var, const(data_addr_const(data_addr(
+	code_info__assign_const_to_var(Var, const(data_addr_const(data_addr(
 		ModuleName, base_typeclass_info(ClassId, Instance))))).
 unify_gen__generate_construction_2(tabling_pointer_constant(PredId, ProcId),
-		Var, Args, _Modes, _, Code) -->
+		Var, Args, _Modes, _, empty) -->
 	( { Args = [] } ->
 		[]
 	;
 		{ error("unify_gen: tabling pointer constant has args") }
 	),
-	{ Code = empty },
 	code_info__get_module_info(ModuleInfo),
 	{ code_util__make_proc_label(ModuleInfo, PredId, ProcId, ProcLabel) },
 	{ module_info_name(ModuleInfo, ModuleName) },
 	{ DataAddr = data_addr(ModuleName, tabling_pointer(ProcLabel)) },
-	code_info__cache_expression(Var, const(data_addr_const(DataAddr))).
+	code_info__assign_const_to_var(Var, const(data_addr_const(DataAddr))).
 unify_gen__generate_construction_2(code_addr_constant(PredId, ProcId),
-		Var, Args, _Modes, _, Code) -->
+		Var, Args, _Modes, _, empty) -->
 	( { Args = [] } ->
 		[]
 	;
 		{ error("unify_gen: address constant has args") }
 	),
-	{ Code = empty },
 	code_info__get_module_info(ModuleInfo),
 	code_info__make_entry_label(ModuleInfo, PredId, ProcId, no, CodeAddr),
-	code_info__cache_expression(Var, const(code_addr_const(CodeAddr))).
+	code_info__assign_const_to_var(Var, const(code_addr_const(CodeAddr))).
 unify_gen__generate_construction_2(
 		pred_closure_tag(PredId, ProcId, EvalMethod),
 		Var, Args, _Modes, _AditiInfo, Code) -->
@@ -440,7 +426,8 @@
 	    ( { CallArgs = [] } ->
 		% if there are no new arguments, we can just use the old
 		% closure
-		code_info__produce_variable(CallPred, Code, Value)
+		code_info__assign_var_to_var(Var, CallPred),
+		{ Code = empty }
 	    ;
 		code_info__get_next_label(LoopStart),
 		code_info__get_next_label(LoopTest),
@@ -505,12 +492,10 @@
 		code_info__release_reg(LoopCounter),
 		code_info__release_reg(NumOldArgs),
 		code_info__release_reg(NewClosure),
-		{ Code = tree(Code1, tree(Code2, Code3)) },
-		{ Value = lval(NewClosure) }
+		code_info__assign_lval_to_var(Var, NewClosure),
+		{ Code = tree(Code1, tree(Code2, Code3)) }
 	    )
 	;
-		{ Code = empty },
-
 		code_info__make_entry_label(ModuleInfo,
 			PredId, ProcId, no, CodeAddr),
 		{ code_util__extract_proc_label_from_code_addr(CodeAddr,
@@ -565,11 +550,8 @@
 			yes(const(int_const(NumArgs)))
 			| PredArgs
 		] },
-		code_info__get_next_cell_number(ClosureCellNo),
-		{ Value = create(0, Vector, uniform(no), can_be_either,
-			ClosureCellNo, "closure", Reuse) }
-	),
-	code_info__cache_expression(Var, Value).
+		code_info__assign_cell_to_var(Var, 0, Vector, "closure", Code)
+	).
 
 :- pred unify_gen__generate_extra_closure_args(list(prog_var), lval, lval,
 		code_tree, code_info, code_info).
@@ -724,23 +706,23 @@
 			{ error("unify_gen__generate_det_deconstruction: no_tag: arity != 1") }
 		)
 	;
-		{ Tag = unshared_tag(UnsharedTag) },
+		{ Tag = unshared_tag(Ptag) },
 		{ Rval = var(Var) },
 		{ unify_gen__make_fields_and_argvars(Args, Rval, 0,
-			UnsharedTag, Fields, ArgVars) },
+			Ptag, Fields, ArgVars) },
 		unify_gen__var_types(Args, ArgTypes),
 		unify_gen__generate_unify_args(Fields, ArgVars,
 			Modes, ArgTypes, Code)
 	;
-		{ Tag = shared_remote_tag(Bits0, _Num0) },
+		{ Tag = shared_remote_tag(Ptag, _Sectag1) },
 		{ Rval = var(Var) },
 		{ unify_gen__make_fields_and_argvars(Args, Rval, 1,
-			Bits0, Fields, ArgVars) },
+			Ptag, Fields, ArgVars) },
 		unify_gen__var_types(Args, ArgTypes),
 		unify_gen__generate_unify_args(Fields, ArgVars,
 			Modes, ArgTypes, Code)
 	;
-		{ Tag = shared_local_tag(_Bits1, _Num1) },
+		{ Tag = shared_local_tag(_Ptag, _Sectag2) },
 		{ Code = empty } % if this is det, then nothing happens
 	).
 
@@ -832,7 +814,7 @@
 	->
 		unify_gen__generate_sub_assign(R, L, Code)
 	;
-			% Input - Output== assignment <-
+			% Output - Input== assignment <-
 		{ LeftMode = top_out },
 		{ RightMode = top_in }
 	->
@@ -854,24 +836,12 @@
 							code_info, code_info).
 :- mode unify_gen__generate_sub_assign(in, in, out, in, out) is det.
 
-	% Assignment between two lvalues - cannot cache [yet]
-	% so generate immediate code
-	% If the destination of the assignment contains any vars,
-	% we need to materialize those before we can do the assignment.
-unify_gen__generate_sub_assign(lval(Lval0), lval(Rval), Code) -->
-	code_info__materialize_vars_in_rval(lval(Lval0), NewLval,
-		MaterializeCode),
-	(
-		{ NewLval = lval(Lval) }
-	->
-		{ Code = tree(MaterializeCode, node([
-			assign(Lval, lval(Rval)) - "Copy field"
-		])) }
-	;
-		{ error("unify_gen__generate_sub_assign: lval vanished with lval") }
-	).
-	% assignment from a variable to an lvalue - cannot cache
-	% so generate immediately
+	% Assignment between two lvalues - cannot happen.
+unify_gen__generate_sub_assign(lval(_Lval0), lval(_Rval), _Code) -->
+	{ error("unify_gen__generate_sub_assign: lval/lval") }.
+
+	% Assignment from a variable to an lvalue - cannot cache
+	% so generate immediately.
 unify_gen__generate_sub_assign(lval(Lval0), ref(Var), Code) -->
 	code_info__produce_variable(Var, SourceCode, Source),
 	code_info__materialize_vars_in_rval(lval(Lval0), NewLval,
@@ -888,23 +858,19 @@
 	;
 		{ error("unify_gen__generate_sub_assign: lval vanished with ref") }
 	).
-	% assignment to a variable, so cache it.
-unify_gen__generate_sub_assign(ref(Var), lval(Rval), empty) -->
-	(
-		code_info__variable_is_forward_live(Var)
-	->
-		code_info__cache_expression(Var, lval(Rval))
+	% Assignment to a variable, so cache it.
+unify_gen__generate_sub_assign(ref(Var), lval(Lval), empty) -->
+	( code_info__variable_is_forward_live(Var) ->
+		code_info__assign_lval_to_var(Var, Lval)
 	;
-		{ true }
+		[]
 	).
-	% assignment to a variable, so cache it.
+	% Assignment to a variable, so cache it.
 unify_gen__generate_sub_assign(ref(Lvar), ref(Rvar), empty) -->
-	(
-		code_info__variable_is_forward_live(Lvar)
-	->
-		code_info__cache_expression(Lvar, var(Rvar))
+	( code_info__variable_is_forward_live(Lvar) ->
+		code_info__assign_var_to_var(Lvar, Rvar)
 	;
-		{ true }
+		[]
 	).
 
 %---------------------------------------------------------------------------%
Index: compiler/var_locn.m
===================================================================
RCS file: var_locn.m
diff -N var_locn.m
--- /dev/null	Wed Jul 26 16:10:00 2000
+++ var_locn.m	Thu Aug  3 13:27:17 2000
@@ -0,0 +1,2208 @@
+%---------------------------------------------------------------------------%
+% Copyright (C) 2000 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%---------------------------------------------------------------------------%
+%
+% File: var_locn.m
+% Author: zs.
+%
+% This module defines a set of predicates that operate on the abstract
+% 'var_locn_info' structure which maintains information about where variables
+% are stored, what their values are if they are not stored anywhere,
+% and which registers are reserved for purposes such as holding the arguments
+% of calls and tags that are to be switched upon.
+
+%----------------------------------------------------------------------------%
+
+:- module var_locn.
+
+:- interface.
+
+:- import_module prog_data, hlds_goal, llds, options.
+:- import_module bool, map, set, list, assoc_list, std_util.
+
+:- type var_locn_info.
+
+%	var_locn__init_state(Arguments, Liveness, Varset,
+%			StackSlots, FollowVars, Opts, VarLocnInfo)
+%		Produces an initial state of the VarLocnInfo given
+%		an association list of variables and lvalues. The initial
+%		state places the given variables at their corresponding
+%		locations, with the exception of variables which are not in
+%		Liveness (this corresponds to input arguments that are not
+%		used in the body). The Varset parameter contains a mapping from
+%		variables to names, which is used when code is generated
+%		to provide meaningful comments. StackSlots maps each variable
+%		to its stack slot, if it has one. FollowVars is the initial
+%		follow_vars set; such sets give guidance as to what lvals
+%		(if any) each variable will be needed in next. Opts gives
+%		the table of options; this is used to decide what expressions
+%		are considered constants.
+
+:- pred var_locn__init_state(assoc_list(prog_var, lval)::in, set(prog_var)::in,
+	prog_varset::in, stack_slots::in, follow_vars::in, option_table::in,
+	var_locn_info::out) is det.
+
+%	var_locn__reinit_state(VarLocs, VarLocnInfo0, VarLocnInfo)
+%		Produces a new state of the VarLocnInfo in which the static
+%		and mostly static information (stack slot map, follow vars map,
+%		varset, option settings) comes from VarLocnInfo0 but the
+%		dynamic state regarding variable locations is thrown away
+%		and then rebuilt from the information in VarLocs, an
+%		association list of variables and lvals. The new state
+%		places the given variables at their corresponding locations.
+
+:- pred var_locn__reinit_state(assoc_list(prog_var, lval)::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__clobber_all_regs(VarLocnInfo0, VarLocnInfo)
+%		Modifies the state VarLocnInfo0 to produce VarLocnInfo
+%		in which all variables stored in registers are clobbered.
+
+:- pred var_locn__clobber_all_regs(var_locn_info::in, var_locn_info::out)
+	is det.
+
+%	var_locn__clobber_regs(Regs, VarLocnInfo0, VarLocnInfo)
+%		Modifies the state VarLocnInfo0 to produce VarLocnInfo
+%		in which all variables stored in Regs (a list of lvals
+%		which should contain only registers) are clobbered.
+
+:- pred var_locn__clobber_regs(list(lval)::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__set_magic_var_location(Var, Lval, VarLocnInfo0, VarLocnInfo)
+%		Modifies VarLocnInfo0 to produce VarLocnInfo in which
+%		Var is *magically* stored in Lval. Does not care if Lval
+%		is already in use; it overwrites it with the new information.
+%		Used to implement the ends of erroneous branches.
+
+:- pred var_locn__set_magic_var_location(prog_var::in, lval::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__check_and_set_magic_var_location(Var, Lval,
+%			VarLocnInfo0, VarLocnInfo)
+%		Modifies VarLocnInfo0 to produce VarLocnInfo in which
+%		Var is *magically* stored in Lval. (The caller usually
+%		generates code to perform this magic.) Aborts if Lval
+%		is already in use.
+
+:- pred var_locn__check_and_set_magic_var_location(prog_var::in, lval::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__lval_in_use(Lval, VarLocnInfo0, VarLocnInfo)
+%		Succeeds iff Lval, which should be a register or stack slot,
+%		holds (a path to) a variable or is otherwise reserved.
+
+:- pred var_locn__lval_in_use(lval::in, var_locn_info::in, var_locn_info::out)
+	is semidet.
+
+%	var_locn__var_becomes_dead(Var, FirstTime, VarLocnInfo0, VarLocnInfo)
+%		Frees any code generator resources used by Var in VarLocnInfo0
+%		to produce VarLocnInfo. FirstTime should be no if this same
+%		operation may already have been executed on Var; otherwise,
+%		var_locn__var_becomes_dead will throw an exception if it does
+%		not know about Var.
+:- pred var_locn__var_becomes_dead(prog_var::in, bool::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__assign_var_to_var(Var, AssignedVar,
+%			VarLocnInfo0, VarLocnInfo)
+%		Reflects the effect of the assignment Var := AssignedVar in the
+%		state of VarLocnInfo0 to yield VarLocnInfo.
+
+:- pred var_locn__assign_var_to_var(prog_var::in, prog_var::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__assign_lval_to_var(Var, Lval, VarLocnInfo0, VarLocnInfo)
+%		Reflects the effect of the assignment Var := lval(Lval) in the
+%		state of VarLocnInfo0 to yield VarLocnInfo.
+
+:- pred var_locn__assign_lval_to_var(prog_var::in, lval::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__assign_const_to_var(Var, ConstRval,
+%			VarLocnInfo0, VarLocnInfo)
+%		Reflects the effect of the assignment Var := const(ConstRval)
+%		in the state of VarLocnInfo0 to yield VarLocnInfo.
+
+:- pred var_locn__assign_const_to_var(prog_var::in, rval::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__assign_expr_to_var(Var, Rval, Code,
+%			VarLocnInfo0, VarLocnInfo)
+%		Generates code to execute the assignment Var := Expr, and
+%		updates the state of VarLocnInfo0 accordingly.
+%
+%		Expr must contain no lvals, although it may (and typically
+%		will) refer to the values of other variables through rvals
+%		of the form var(_).
+
+:- pred var_locn__assign_expr_to_var(prog_var::in, rval::in, code_tree::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__assign_cell_to_var(Var, Ptag, Vector, CellNum, TypeMsg, Code,
+%			VarLocnInfo0, VarLocnInfo)
+%		Generates code to assign to Var a pointer, tagged by Ptag, to
+%		the cell whose contents are given by the other arguments,
+%		and updates the state of VarLocnInfo0 accordingly.
+
+:- pred var_locn__assign_cell_to_var(prog_var::in, tag::in,
+	list(maybe(rval))::in, int::in, string::in, code_tree::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__place_var(Var, Lval, Code, VarLocnInfo0, VarLocnInfo)
+%		Produces Code and a modified version of VarLocnInfo0,
+%		VarLocnInfo which places the value of Var in Lval.
+
+:- pred var_locn__place_var(prog_var::in, lval::in, code_tree::out,
+		var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__place_vars(VarLocns, Code, VarLocnInfo0, VarLocnInfo)
+%		Produces Code and a modified version of VarLocnInfo0,
+%		VarLocnInfo which places the value of each variable
+%		mentioned in VarLocns into the corresponding location.
+
+:- pred var_locn__place_vars(assoc_list(prog_var, lval)::in, code_tree::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__produce_var(Var, Rval, Code, VarLocnInfo0, VarLocnInfo)
+%		Return the preferred way to refer to the value of Var
+%		(which may be a const rval, or the value in an lval).
+%
+% 		If Var is currently a cached expression, then produce_var
+%		will generate Code to evaluate the expression and put it
+%		into an lval. (Since the code generator can ask for a variable
+%		to be produced more than once, this is necessary to prevent
+%		the expression, which may involve a possibly large number
+%		of operations, from being evaluated several times.) Otherwise,
+%		Code will be empty.
+
+:- pred var_locn__produce_var(prog_var::in, rval::out, code_tree::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__produce_var_in_reg(Var, Lval, Code,
+%			VarLocnInfo0, VarLocnInfo)
+%		Produces a code fragment Code to evaluate Var if necessary
+%		and provide it as an Lval of the form reg(_).
+
+:- pred var_locn__produce_var_in_reg(prog_var::in, lval::out, code_tree::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__produce_var_in_reg_or_stack(Var, FollowVars, Lval, Code,
+%			VarLocnInfo0, VarLocnInfo)
+%		Produces a code fragment Code to evaluate Var if necessary
+%		and provide it as an Lval of the form reg(_), stackvar(_),
+%		or framevar(_).
+
+:- pred var_locn__produce_var_in_reg_or_stack(prog_var::in, lval::out,
+	code_tree::out, var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__acquire_reg(Lval, VarLocnInfo0, VarLocnInfo)
+%		Finds an unused register and marks it as 'in use'.
+
+:- pred var_locn__acquire_reg(lval::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__acquire_reg_require_given(Reg, Lval,
+%			VarLocInfo0, VarLocInfo)
+%		Marks Reg, which must be an unused register, as 'in use'.
+
+:- pred var_locn__acquire_reg_require_given(lval::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__acquire_reg_prefer_given(Pref, Lval,
+%			VarLocInfo0, VarLocInfo)
+%		Finds an unused register, and marks it as 'in use'.
+%		If Pref itself is free, assigns that.
+
+:- pred var_locn__acquire_reg_prefer_given(int::in, lval::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__acquire_reg_start_at_given(Start, Lval,
+%			VarLocInfo0, VarLocInfo)
+%		Finds an unused register, and marks it as 'in use'.
+%		It starts the search at the one numbered Start,
+%		continuing towards higher register numbers.
+
+:- pred var_locn__acquire_reg_start_at_given(int::in, lval::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__release_reg(Lval, VarLocnInfo, VarLocnInfo)
+%		Marks a previously acquired reg as no longer 'in use'.
+
+:- pred var_locn__release_reg(lval::in, var_locn_info::in, var_locn_info::out)
+	is det.
+
+%	var_locn__lock_regs(N, Exceptions, VarLocnInfo, VarLocnInfo)
+%		Prevents registers r1 through rN from being reused, even if
+%		there are no variables referring to them, with the exceptions
+%		of the registers named in Exceptions, which however can only be
+%		used to store their corresponding variables. Should be followed
+%		by a call to var_locn__unlock_regs.
+
+:- pred var_locn__lock_regs(int::in, assoc_list(prog_var, lval)::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__unlock_regs(VarLocnInfo0, VarLocnInfo)
+%		Undoes a lock operation.
+
+:- pred var_locn__unlock_regs(var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__clear_r1(Code)
+%		Produces a code fragment Code to move whatever is in r1
+%		to some other register, if r1 is live.  This is used
+%		prior to semidet pragma c_codes.
+
+:- pred var_locn__clear_r1(code_tree::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__materialize_vars_in_lval(Lval, FinalLval,
+%			VarLocnInfo0, VarLocnInfo)
+%		For every variable in Lval, substitutes the value of the
+%		variable and returns it as FinalLval. VarLocnInfo0 is unchanged
+%		(it is returned as VarLocnInfo to allow the predicate to be
+%		used in DCGs).
+
+:- pred var_locn__materialize_vars_in_lval(lval::in, lval::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__get_var_locations(VarLocnInfo, Locations)
+%		Returns a map from each live variable that occurs in
+%		VarLocnInfo to the set of locations in which it may be found
+%		(which may be empty, if the variable's value is either a known
+%		constant, or an as-yet unevaluated expression).
+
+:- pred var_locn__get_var_locations(var_locn_info::in,
+	map(prog_var, set(lval))::out) is det.
+
+%	var_locn__get_stack_slots(StackSlots)
+%		Returns the table mapping each variable to its stack slot
+%		(if any).
+
+:- pred var_locn__get_stack_slots(stack_slots::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__get_follow_vars(FollowVars)
+%		Returns the table mapping each variable to the lval (if any)
+%		where it is desired next.
+
+:- pred var_locn__get_follow_var_map(follow_vars_map::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__get_next_non_reserved(NonRes)
+%		Returns the number of the first register which is free for
+%		general use.
+
+:- pred var_locn__get_next_non_reserved(int::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__set_follow_vars(FollowVars)
+%		Sets the table mapping each variable to the lval (if any)
+%		where it is desired next, and the number of the first
+%		non-reserved register.
+
+:- pred var_locn__set_follow_vars(follow_vars::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+%	var_locn__max_reg_in_use(MaxReg)
+%		Returns the number of the highest numbered rN register in use.
+
+:- pred var_locn__max_reg_in_use(var_locn_info::in, int::out) is det.
+
+%----------------------------------------------------------------------------%
+%----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module code_util, exprn_aux, options, tree.
+:- import_module getopt, int, string, bag, require, varset, term.
+
+:- type dead_or_alive	--->	dead ; alive.
+
+	% The state of a variable can be one of three kinds: const, cached
+	% and general.
+	%
+	% 1.	The value of the variable is a known constant. In this case,
+	%	the const_rval field will be yes, and the expr_rval field
+	%	will be no. Both the empty set and nonempty sets are valid
+	%	for the locs field. It will start out empty, will become
+	%	nonempty if the variable is placed in some lval, and may
+	%	become empty again if that lval is later overwritten.
+	%
+	% 2.	The value of the variable is not stored anywhere, but its
+	%	definition (an expression involving other variables) is cached.
+	%	In this case, the const_rval field will be no, and the locs
+	%	field will contain the empty set, but the expr_rval field
+	%	will be yes. The variables referred to in the expr_rval field
+	%	will include this variable in their using_vars sets, which
+	%	protects them from deletion from the code generator set until
+	%	the using variable is produced or placed in an lval. When that
+	%	happens, the using variable's state will be transformed to the
+	%	general, third kind, releasing this variable's hold on the
+	%	variables contained in its expr_rval field.
+	%
+	% 3.	The value of the variable is not a constant, nor is the
+	%	variable cached. The locs field will be nonempty, and both
+	%	const_rval and expr_rval will be no.
+
+:- type var_state	--->
+	state(
+		locs		:: set(lval),	% must not contain var(_)
+		const_rval	:: maybe(rval),	% must not contain var(_),
+						% must be constant
+		expr_rval	:: maybe(rval), % will contain var(_),
+						% must not contain lvals
+		using_vars	:: set(prog_var),
+						% the set of vars whose
+						% expr_rval field refers
+						% to this var
+		dead_or_alive	:: dead_or_alive
+						% a dead variable should be
+						% removed from var_state_map
+						% when its using_vars field
+						% becomes empty
+	).
+
+:- type var_state_map	==	map(prog_var, var_state).
+
+
+	% The loc_var_map maps each root lval (register or stack slot)
+	% to the set of variables that depend on that location,
+	% either because they are stored there or because the location
+	% contains a part of the pointer chain that leads to their address.
+	% In concrete terms, this means the set of variables whose var_state's
+	% locs field includes an lval that contains that root lval.
+	%
+	% If a root lval stack slot is unused, then it will either not appear
+	% in the var_loc_map or it will be mapped to an empty set. Allowing
+	% unused root lvals to be mapped to the empty set, and not requiring
+	% their deletion from the map, makes it simpler to manipulate
+	% loc_var_maps using higher-order code.
+
+:- type loc_var_map	==	map(lval, set(prog_var)).
+
+:- type var_locn_info	--->
+	var_locn_info(
+		varset		:: prog_varset,	% The varset from the
+						% proc_info.
+		stack_slots 	:: stack_slots,	% Maps each var to its stack
+						% slot, if it has one.
+		exprn_opts	:: exprn_opts,	% The values of the options
+						% that are relevant to
+						% decisions about which rvals
+						% are constants.
+		follow_vars_map	:: follow_vars_map,
+						% Where vars are needed next.
+		next_non_res	:: int,		% Next register that is not
+						% reserved in follow_vars_map.
+		var_state_map	:: var_state_map,
+						% Documented above.
+		loc_var_map	:: loc_var_map, % Documented above.
+		acquired	:: set(lval),	% Locations that are
+						% temporarily reserved for
+						% purposes such as holding the
+						% tags of variables during
+						% switches.
+		locked		:: int,		% If this slot contains N, then
+						% registers r1 through rN
+						% can only be modified by
+						% a place_var operation,
+						% or by a free_up_lval
+						% operation that moves a
+						% variable to the (free or
+						% freeable) lval associated
+						% with it in the exceptions.
+						% field. Used to implement
+						% calls, pragma_c_codes and the
+						% store_maps at the ends of
+						% branched control structures.
+		exceptions	:: assoc_list(prog_var, lval)
+						% See the documentation of the
+						% locked field above.
+	).
+
+%----------------------------------------------------------------------------%
+
+var_locn__init_state(VarLocs, Liveness, Varset, StackSlots, FollowVars,
+		Options, VarLocnInfo) :-
+	map__init(VarStateMap0),
+	map__init(LocVarMap0),
+	var_locn__init_state_2(VarLocs, yes(Liveness),
+		VarStateMap0, VarStateMap, LocVarMap0, LocVarMap),
+	exprn_aux__init_exprn_opts(Options, ExprnOpts),
+	FollowVars = follow_vars(FollowVarMap, NextNonReserved),
+	set__init(AcquiredRegs),
+	VarLocnInfo = var_locn_info(Varset, StackSlots, ExprnOpts,
+		FollowVarMap, NextNonReserved, VarStateMap, LocVarMap,
+		AcquiredRegs, 0, []).
+
+var_locn__reinit_state(VarLocs, VarLocnInfo0, VarLocnInfo) :-
+	map__init(VarStateMap0),
+	map__init(LocVarMap0),
+	var_locn__init_state_2(VarLocs, no, VarStateMap0, VarStateMap,
+		LocVarMap0, LocVarMap),
+	set__init(AcquiredRegs),
+	VarLocnInfo0 = var_locn_info(Varset, StackSlots, ExprnOpts,
+		FollowVarMap, NextNonReserved, _, _, _, _, _),
+	VarLocnInfo = var_locn_info(Varset, StackSlots, ExprnOpts,
+		FollowVarMap, NextNonReserved, VarStateMap, LocVarMap,
+		AcquiredRegs, 0, []).
+
+:- pred var_locn__init_state_2(assoc_list(prog_var, lval)::in,
+	maybe(set(prog_var))::in, var_state_map::in, var_state_map::out,
+	loc_var_map::in, loc_var_map::out) is det.
+
+var_locn__init_state_2([], _, VarStateMap, VarStateMap, LocVarMap, LocVarMap).
+var_locn__init_state_2([Var - Lval |  Rest], MaybeLiveness,
+		VarStateMap0, VarStateMap, LocVarMap0, LocVarMap) :-
+	require(var_locn__is_root_lval(Lval),
+		"var_locn__init_state_2: unexpected lval"),
+	(
+		MaybeLiveness = yes(Liveness),
+		\+ set__member(Var, Liveness)
+	->
+			% If a variable is not live, then we do not record its
+			% state. If we did, then the variable will never die
+			% (since it is already dead), and the next call to
+			% clobber_regs would throw an exception, since it would
+			% believe that it is throwing away the last location
+			% storing the value of a "live" variable.
+		VarStateMap1 = VarStateMap0,
+		LocVarMap1 = LocVarMap0
+	;
+		( map__search(VarStateMap0, Var, _) ->
+			error("var_locn__init_state_2: repeated variable")
+		;
+			set__singleton_set(NewLocs, Lval),
+			set__init(Using),
+			State = state(NewLocs, no, no, Using, alive),
+			map__det_insert(VarStateMap0, Var, State, VarStateMap1)
+		),
+		( map__search(LocVarMap0, Lval, OldVars) ->
+			set__insert(OldVars, Var, NewVars),
+			map__det_update(LocVarMap0, Lval, NewVars, LocVarMap1)
+		;
+			set__singleton_set(NewVars, Var),
+			map__det_insert(LocVarMap0, Lval, NewVars, LocVarMap1)
+		)
+	),
+	var_locn__init_state_2(Rest, MaybeLiveness, VarStateMap1, VarStateMap,
+		LocVarMap1, LocVarMap).
+
+%----------------------------------------------------------------------------%
+
+var_locn__get_var_locations(VarLocnInfo, VarLocations) :-
+	var_locn__get_var_state_map(VarStateMap, VarLocnInfo, _),
+	map__to_assoc_list(VarStateMap, VarLocList),
+	list__filter_map(var_locn__convert_live_to_lval_set, VarLocList,
+		LiveVarLocList),
+	map__from_assoc_list(LiveVarLocList, VarLocations).
+
+:- pred var_locn__convert_live_to_lval_set(pair(prog_var, var_state)::in,
+	pair(prog_var, set(lval))::out) is semidet.
+
+var_locn__convert_live_to_lval_set(Var - State, Var - Lvals) :-
+	State = state(Lvals, _, _, _, alive).
+
+%----------------------------------------------------------------------------%
+
+var_locn__clobber_all_regs -->
+	{ set__init(Acquired) },
+	var_locn__set_acquired(Acquired),
+	var_locn__set_locked(0),
+	var_locn__set_exceptions([]),
+	var_locn__get_loc_var_map(LocVarMap0),
+	var_locn__get_var_state_map(VarStateMap0),
+	{ map__keys(LocVarMap0, Locs) },
+	{ var_locn__clobber_regs_in_maps(Locs, LocVarMap0, LocVarMap,
+		VarStateMap0, VarStateMap) },
+	var_locn__set_loc_var_map(LocVarMap),
+	var_locn__set_var_state_map(VarStateMap).
+
+var_locn__clobber_regs(Regs) -->
+	var_locn__get_acquired(Acquired0),
+	{ Acquired = set__delete_list(Acquired0, Regs) },
+	var_locn__set_acquired(Acquired),
+	var_locn__get_loc_var_map(LocVarMap0),
+	var_locn__get_var_state_map(VarStateMap0),
+	{ var_locn__clobber_regs_in_maps(Regs, LocVarMap0, LocVarMap,
+		VarStateMap0, VarStateMap) },
+	var_locn__set_loc_var_map(LocVarMap),
+	var_locn__set_var_state_map(VarStateMap).
+
+:- pred var_locn__clobber_regs_in_maps(list(lval)::in,
+	loc_var_map::in, loc_var_map::out,
+	var_state_map::in, var_state_map::out) is det.
+
+var_locn__clobber_regs_in_maps([], LocVarMap, LocVarMap,
+		VarStateMap, VarStateMap).
+var_locn__clobber_regs_in_maps([Lval | Lvals], LocVarMap0, LocVarMap,
+		VarStateMap0, VarStateMap) :-
+	(
+		Lval = reg(_, _),
+		map__search(LocVarMap0, Lval, DependentVarsSet)
+	->
+		map__delete(LocVarMap0, Lval, LocVarMap1),
+		set__to_sorted_list(DependentVarsSet, DependentVars),
+		list__foldl(var_locn__clobber_lval_in_var_state_map(Lval, []),
+			DependentVars, VarStateMap0, VarStateMap1)
+	;
+		LocVarMap1 = LocVarMap0,
+		VarStateMap1 = VarStateMap0
+	),
+	var_locn__clobber_regs_in_maps(Lvals, LocVarMap1, LocVarMap,
+		VarStateMap1, VarStateMap).
+
+:- pred var_locn__clobber_lval_in_var_state_map(lval::in, list(prog_var)::in,
+	prog_var::in, var_state_map::in, var_state_map::out) is det.
+
+var_locn__clobber_lval_in_var_state_map(Lval, OkToDeleteVars, Var,
+		VarStateMap0, VarStateMap) :-
+	(
+		var_locn__try_clobber_lval_in_var_state_map(Lval,
+			OkToDeleteVars, Var, VarStateMap0, VarStateMap1)
+	->
+		VarStateMap = VarStateMap1
+	;
+		error("var_locn__clobber_lval_in_var_state_map: empty state")
+	).
+
+% Try to record in VarStateMap that Var is no longer reachable through (paths
+% including) Lval. If this deletes the last possible place where the value of
+% Var can be found, and Var is not in OkToDeleteVars, then fail.
+
+:- pred var_locn__try_clobber_lval_in_var_state_map(lval::in,
+	list(prog_var)::in, prog_var::in,
+	var_state_map::in, var_state_map::out) is semidet.
+
+var_locn__try_clobber_lval_in_var_state_map(Lval, OkToDeleteVars, Var,
+		VarStateMap0, VarStateMap) :-
+	map__lookup(VarStateMap0, Var, State0),
+	State0 = state(LvalSet0, MaybeConstRval, MaybeExprRval, Using,
+		DeadOrAlive),
+	LvalSet = set__filter(var_locn__lval_does_not_support_lval(Lval),
+		LvalSet0),
+	State = state(LvalSet, MaybeConstRval, MaybeExprRval, Using,
+		DeadOrAlive),
+	(
+		var_locn__nonempty_state(State)
+	;
+		list__member(Var, OkToDeleteVars)
+	;
+		DeadOrAlive = dead,
+		set__to_sorted_list(Using, UsingVars),
+		var_locn__recursive_using_vars_dead_and_ok_to_delete(UsingVars,
+			VarStateMap0, OkToDeleteVars)
+	),
+	map__det_update(VarStateMap0, Var, State, VarStateMap).
+
+:- pred var_locn__recursive_using_vars_dead_and_ok_to_delete(
+	list(prog_var)::in, var_state_map::in, list(prog_var)::in) is semidet.
+
+var_locn__recursive_using_vars_dead_and_ok_to_delete([], _, _).
+var_locn__recursive_using_vars_dead_and_ok_to_delete([Var | Vars],
+		VarStateMap, OkToDeleteVars) :-
+	(
+		list__member(Var, OkToDeleteVars)
+	;
+		map__lookup(VarStateMap, Var, State),
+		State = state(_, _, _, Using, DeadOrAlive),
+		DeadOrAlive = dead,
+		set__to_sorted_list(Using, UsingVars),
+		var_locn__recursive_using_vars_dead_and_ok_to_delete(UsingVars,
+			VarStateMap, OkToDeleteVars)
+	),
+	var_locn__recursive_using_vars_dead_and_ok_to_delete(Vars,
+		VarStateMap, OkToDeleteVars).
+
+%----------------------------------------------------------------------------%
+
+var_locn__assign_var_to_var(Var, OldVar) -->
+	var_locn__check_var_is_unknown(Var),
+
+	var_locn__get_var_state_map(VarStateMap0),
+	{ map__lookup(VarStateMap0, OldVar, OldState0) },
+	{ OldState0 = state(Lvals, MaybeConstRval, MaybeExprRval,
+		Using0, DeadOrAlive) },
+	{
+		MaybeExprRval = yes(_),
+		State = state(Lvals, MaybeConstRval, yes(var(OldVar)),
+			set__init, alive),
+		set__insert(Using0, Var, Using),
+		OldState = state(Lvals, MaybeConstRval, MaybeExprRval,
+			Using, DeadOrAlive),
+		map__det_update(VarStateMap0, OldVar, OldState, VarStateMap1)
+	;
+		MaybeExprRval = no,
+		set__init(Empty),
+		State = state(Lvals, MaybeConstRval, no, Empty, alive),
+		VarStateMap1 = VarStateMap0
+	},
+	{ map__det_insert(VarStateMap1, Var, State, VarStateMap) },
+	var_locn__set_var_state_map(VarStateMap),
+
+	var_locn__get_loc_var_map(LocVarMap0),
+	{ var_locn__make_var_depend_on_lvals_roots(Var, Lvals,
+		LocVarMap0, LocVarMap) },
+	var_locn__set_loc_var_map(LocVarMap).
+
+%----------------------------------------------------------------------------%
+
+var_locn__assign_lval_to_var(Var, Lval0) -->
+	var_locn__check_var_is_unknown(Var),
+
+	(
+		{ Lval0 = field(yes(Ptag), var(BaseVar),
+			const(int_const(Offset))) }
+	->
+		var_locn__get_var_state_map(VarStateMap0),
+		{ map__lookup(VarStateMap0, BaseVar, BaseState) },
+		{ BaseState = state(BaseVarLvals, MaybeConstBaseVarRval,
+			MaybeExprRval, _UsingVars, _DeadOrAlive) },
+		{ require(unify(MaybeExprRval, no),
+			"var_locn__assign_lval_to_var: field of expr") },
+		{
+			MaybeConstBaseVarRval = yes(BaseVarRval),
+			BaseVarRval = create(Ptag, BaseVarArgs, _, _, _, _, _)
+		->
+			list__index0_det(BaseVarArgs, Offset, SelectedArg),
+			MaybeConstRval = SelectedArg
+		;
+			MaybeConstRval = no
+		},
+		{ Lvals = set__map(var_locn__add_field_offset(yes(Ptag),
+			const(int_const(Offset))), BaseVarLvals) },
+		{ set__init(Using) },
+		{ State = state(Lvals, MaybeConstRval, no, Using, alive) },
+		{ map__det_insert(VarStateMap0, Var, State, VarStateMap) },
+		var_locn__set_var_state_map(VarStateMap),
+
+		var_locn__get_loc_var_map(LocVarMap0),
+		{ var_locn__make_var_depend_on_lvals_roots(Var, Lvals,
+			LocVarMap0, LocVarMap) },
+		var_locn__set_loc_var_map(LocVarMap)
+	;
+		var_locn__get_var_state_map(VarStateMap0),
+		{ var_locn__materialize_vars_in_lval(Lval0, VarStateMap0,
+			Lval) },
+		{ set__singleton_set(LvalSet, Lval) },
+		{ State = state(LvalSet, no, no, set__init, alive) },
+		{ map__det_insert(VarStateMap0, Var, State, VarStateMap) },
+		var_locn__set_var_state_map(VarStateMap),
+
+		var_locn__get_loc_var_map(LocVarMap0),
+		{ var_locn__make_var_depend_on_lval_roots(Var, Lval,
+			LocVarMap0, LocVarMap) },
+		var_locn__set_loc_var_map(LocVarMap)
+	).
+
+:- func var_locn__add_field_offset(maybe(tag), rval, lval) = lval.
+
+var_locn__add_field_offset(Ptag, Offset, Base) =
+	field(Ptag, lval(Base), Offset).
+
+%----------------------------------------------------------------------------%
+
+var_locn__assign_const_to_var(Var, ConstRval0) -->
+	var_locn__check_var_is_unknown(Var),
+
+	var_locn__get_var_state_map(VarStateMap0),
+	var_locn__get_exprn_opts(ExprnOpts),
+	(
+		{ var_locn__expr_is_constant(ConstRval0, VarStateMap0,
+			ExprnOpts, ConstRval) }
+	->
+		{ State = state(set__init, yes(ConstRval), no,
+			set__init, alive) },
+		{ map__det_insert(VarStateMap0, Var, State, VarStateMap) },
+		var_locn__set_var_state_map(VarStateMap)
+	;
+		{ error("var_locn__set_var_state_map: supposed constant isn't") }
+	).
+
+%----------------------------------------------------------------------------%
+
+var_locn__assign_expr_to_var(Var, Rval, empty) -->
+	var_locn__check_var_is_unknown(Var),
+
+	var_locn__get_var_state_map(VarStateMap0),
+	{ State = state(set__init, no, yes(Rval), set__init, alive) },
+	{ map__det_insert(VarStateMap0, Var, State, VarStateMap1) },
+
+	{ exprn_aux__vars_in_rval(Rval, ContainedVars0) },
+	{ list__remove_dups(ContainedVars0, ContainedVars) },
+	{ var_locn__add_use_refs(ContainedVars, Var, VarStateMap1,
+		VarStateMap) },
+	var_locn__set_var_state_map(VarStateMap).
+
+:- pred var_locn__add_use_refs(list(prog_var)::in, prog_var::in,
+	var_state_map::in, var_state_map::out) is det.
+
+var_locn__add_use_refs([], _, VarStateMap, VarStateMap).
+var_locn__add_use_refs([ContainedVar | ContainedVars], UsingVar,
+		VarStateMap0, VarStateMap) :-
+	map__lookup(VarStateMap0, ContainedVar, State0),
+	State0 = state(Lvals, MaybeConstRval, MaybeExprRval,
+		Using0, DeadOrAlive),
+	set__insert(Using0, UsingVar, Using),
+	State = state(Lvals, MaybeConstRval, MaybeExprRval,
+		Using, DeadOrAlive),
+	map__det_update(VarStateMap0, ContainedVar, State, VarStateMap1),
+	var_locn__add_use_refs(ContainedVars, UsingVar,
+		VarStateMap1, VarStateMap).
+
+%----------------------------------------------------------------------------%
+
+var_locn__assign_cell_to_var(Var, Ptag, Vector, CellNum, TypeMsg, Code) -->
+	{ Reuse = no },
+	{ CellRval0 = create(Ptag, Vector, uniform(no), can_be_either,
+		CellNum, TypeMsg, Reuse) },
+	(
+		var_locn__get_var_state_map(VarStateMap),
+		var_locn__get_exprn_opts(ExprnOpts),
+		{ var_locn__expr_is_constant(CellRval0, VarStateMap, ExprnOpts,
+			CellRval) }
+	->
+		var_locn__assign_const_to_var(Var, CellRval),
+		{ Code = empty }
+	;
+		var_locn__assign_dynamic_cell_to_var(Var, Ptag, Vector,
+			TypeMsg, Code)
+	).
+
+:- pred var_locn__assign_dynamic_cell_to_var(prog_var::in, tag::in,
+	list(maybe(rval))::in, string::in, code_tree::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__assign_dynamic_cell_to_var(Var, Ptag, Vector, TypeMsg, Code) -->
+	var_locn__check_var_is_unknown(Var),
+
+	var_locn__select_preferred_reg_or_stack(Var, Lval),
+	var_locn__get_var_name(Var, VarName),
+	{ list__length(Vector, Size) },
+	{ CellCode = node([
+		incr_hp(Lval, yes(Ptag), const(int_const(Size)), TypeMsg)
+			- string__append("Allocating heap for ", VarName)
+	]) },
+	var_locn__set_magic_var_location(Var, Lval),
+	var_locn__assign_cell_args(Vector, yes(Ptag), lval(Lval), 0, ArgsCode),
+	{ Code = tree(CellCode, ArgsCode) }.
+
+:- pred var_locn__assign_cell_args(list(maybe(rval))::in,
+	maybe(tag)::in, rval::in, int::in, code_tree::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__assign_cell_args([], _, _, _, empty) --> [].
+var_locn__assign_cell_args([MaybeRval0 | MaybeRvals0], Ptag, Base, Offset,
+		Code) -->
+	( { MaybeRval0 = yes(Rval0) } ->
+		{ Target = field(Ptag, Base, const(int_const(Offset))) },
+		( { Rval0 = var(Var) } ->
+			var_locn__produce_var_maybe_expr(Var, no, Rval),
+			var_locn__add_additional_lval_for_var(Var, Target),
+			var_locn__get_var_name(Var, VarName),
+			{ Comment = string__append("assigning from ",
+				VarName) }
+		; { Rval0 = const(_) } ->
+			{ Rval = Rval0 },
+			{ Comment = "assigning field from const" }
+		; { Rval0 = create(_, _, _, _, _, _, _) } ->
+			{ Rval = Rval0 },
+			{ Comment = "assigning field from const struct" }
+		;
+			{ error("var_locn__assign_cell_args: unknown rval") }
+		),
+		{ ThisCode = node([
+			assign(Target, Rval) - Comment
+		]) }
+	;
+		{ ThisCode = empty }
+	),
+	var_locn__assign_cell_args(MaybeRvals0, Ptag, Base, Offset + 1,
+		RestCode),
+	{ Code = tree(ThisCode, RestCode) }.
+
+%----------------------------------------------------------------------------%
+
+% Record that Var is now available in Lval, as well as in the locations
+% where it was available before.
+
+:- pred var_locn__add_additional_lval_for_var(prog_var::in, lval::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__add_additional_lval_for_var(Var, Lval) -->
+	var_locn__get_loc_var_map(LocVarMap0),
+	{ var_locn__make_var_depend_on_lval_roots(Var, Lval,
+		LocVarMap0, LocVarMap) },
+	var_locn__set_loc_var_map(LocVarMap),
+
+	var_locn__get_var_state_map(VarStateMap0),
+	{ map__lookup(VarStateMap0, Var, State0) },
+	{ State0 = state(LvalSet0, MaybeConstRval, MaybeExprRval0,
+		Using, DeadOrAlive) },
+	{ set__insert(LvalSet0, Lval, LvalSet) },
+	{ State = state(LvalSet, MaybeConstRval, no, Using, DeadOrAlive) },
+	{ map__det_update(VarStateMap0, Var, State, VarStateMap) },
+	var_locn__set_var_state_map(VarStateMap),
+
+	var_locn__remove_use_refs(MaybeExprRval0, Var).
+
+:- pred var_locn__remove_use_refs(maybe(rval)::in, prog_var::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__remove_use_refs(MaybeExprRval, UsingVar) -->
+	(
+		{ MaybeExprRval = yes(ExprRval) },
+		{ exprn_aux__vars_in_rval(ExprRval, ContainedVars0) },
+		{ list__remove_dups(ContainedVars0, ContainedVars) },
+		var_locn__remove_use_refs_2(ContainedVars, UsingVar)
+	;
+		{ MaybeExprRval = no }
+	).
+
+:- pred var_locn__remove_use_refs_2(list(prog_var)::in, prog_var::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__remove_use_refs_2([], _) --> [].
+var_locn__remove_use_refs_2([ContainedVar | ContainedVars], UsingVar) -->
+	var_locn__get_var_state_map(VarStateMap0),
+	{ map__lookup(VarStateMap0, ContainedVar, State0) },
+	{ State0 = state(Lvals, MaybeConstRval, MaybeExprRval,
+		Using0, DeadOrAlive) },
+	{ set__remove(Using0, UsingVar, Using1) ->
+		Using = Using1
+	;
+		error("var_locn__remove_use_refs_2: using ref not present")
+	},
+	{ State = state(Lvals, MaybeConstRval, MaybeExprRval,
+		Using, DeadOrAlive) },
+	{ map__det_update(VarStateMap0, ContainedVar, State,
+		VarStateMap) },
+	var_locn__set_var_state_map(VarStateMap),
+	(
+		{ set__empty(Using) },
+		{ DeadOrAlive = dead }
+	->
+		var_locn__var_becomes_dead(ContainedVar, no)
+	;
+		[]
+	),
+	var_locn__remove_use_refs_2(ContainedVars, UsingVar).
+
+%----------------------------------------------------------------------------%
+
+% Check that Lval was previously not in use, and record that Var has
+% "magically" appeared there (i.e. our caller has arranged for it to be put
+% there).
+
+var_locn__check_and_set_magic_var_location(Var, Lval) -->
+	( var_locn__lval_in_use(Lval) ->
+		{ error("var_locn__check_and_set_magic_var_location: in use") }
+	;
+		var_locn__set_magic_var_location(Var, Lval)
+	).
+
+% Record that Var has "magically" appeared in Lval (i.e. our caller has
+% arranged for it to be put there). Var must not have been previously known.
+
+var_locn__set_magic_var_location(Var, Lval) -->
+	var_locn__get_loc_var_map(LocVarMap0),
+	{ var_locn__make_var_depend_on_lval_roots(Var, Lval,
+		LocVarMap0, LocVarMap) },
+	var_locn__set_loc_var_map(LocVarMap),
+
+	var_locn__get_var_state_map(VarStateMap0),
+	{ set__singleton_set(LvalSet, Lval) },
+	{ State = state(LvalSet, no, no, set__init, alive) },
+	{ map__det_insert(VarStateMap0, Var, State, VarStateMap) },
+	var_locn__set_var_state_map(VarStateMap).
+
+%----------------------------------------------------------------------------%
+
+:- pred var_locn__check_var_is_unknown(prog_var::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__check_var_is_unknown(Var) -->
+	var_locn__get_var_state_map(VarStateMap0),
+	( { map__search(VarStateMap0, Var, _) } ->
+		var_locn__get_var_name(Var, Name),
+		{ string__append("var_locn__assign_to_var: existing definition of variable ",
+			Name, Msg) },
+		{ error(Msg) }
+	;
+		[]
+	).
+
+%----------------------------------------------------------------------------%
+
+var_locn__produce_var(Var, Rval, Code) -->
+	var_locn__get_var_state_map(VarStateMap),
+	{ map__lookup(VarStateMap, Var, State) },
+	{ State = state(Lvals, MaybeConstRval, _, _, _) },
+	{ set__to_sorted_list(Lvals, LvalsList) },
+	(
+		{ var_locn__maybe_select_lval_or_rval(LvalsList,
+			MaybeConstRval, Rval1) }
+	->
+		{ Rval = Rval1 },
+		{ Code = empty }
+	;
+		var_locn__select_preferred_reg(Var, Lval),
+		var_locn__place_var(Var, Lval, Code),
+		{ Rval = lval(Lval) }
+	).
+
+var_locn__produce_var_in_reg(Var, Lval, Code) -->
+	var_locn__get_var_state_map(VarStateMap),
+	{ map__lookup(VarStateMap, Var, State) },
+	{ State = state(Lvals, _, _, _, _) },
+	{ set__to_sorted_list(Lvals, LvalList) },
+	( { var_locn__select_reg_lval(LvalList, SelectLval) } ->
+		{ Lval = SelectLval },
+		{ Code = empty }
+	;
+		var_locn__select_preferred_reg(Var, Lval),
+		var_locn__place_var(Var, Lval, Code)
+	).
+
+var_locn__produce_var_in_reg_or_stack(Var, Lval, Code) -->
+	var_locn__get_var_state_map(VarStateMap),
+	{ map__lookup(VarStateMap, Var, State) },
+	{ State = state(Lvals, _, _, _, _) },
+	{ set__to_sorted_list(Lvals, LvalList) },
+	( { var_locn__select_reg_or_stack_lval(LvalList, SelectLval) } ->
+		{ Lval = SelectLval },
+		{ Code = empty }
+	;
+		var_locn__select_preferred_reg_or_stack(Var, Lval),
+		var_locn__place_var(Var, Lval, Code)
+	).
+
+:- pred var_locn__produce_var_maybe_expr(prog_var::in, maybe(lval)::in,
+	rval::out, var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__produce_var_maybe_expr(Var, MaybePrefer, Rval) -->
+	var_locn__get_var_state_map(VarStateMap),
+	{ var_locn__select_expr_for_var(Var, VarStateMap, MaybePrefer, Rval) }.
+
+%----------------------------------------------------------------------------%
+
+var_locn__clear_r1(Code) -->
+	var_locn__free_up_lval(reg(r, 1), [], [], Code),
+
+	var_locn__get_loc_var_map(LocVarMap0),
+	var_locn__get_var_state_map(VarStateMap0),
+	{ var_locn__clobber_regs_in_maps([reg(r, 1)], LocVarMap0, LocVarMap,
+		VarStateMap0, VarStateMap) },
+	var_locn__set_loc_var_map(LocVarMap),
+	var_locn__set_var_state_map(VarStateMap).
+
+% If we are asked to place several variables, then we must make sure that in
+% the process of freeing up an lval for one variable, we do not save its
+% previous contents to a location that VarLocns assigns to another variable.
+% This is why we lock the registers used by VarLocns. (We don't need to lock
+% stack slots, since stack slot allocation is required to ensure that the sets
+% of variables that need to be save across calls or at entries to goals with
+% resume points all have distinct stack slots.) However, we do make one
+% exception: if the variable being moved by a freeing up operation is in
+% VarLocns, then it is OK to move it to the location assigned to it by
+% VarLocns.
+
+var_locn__place_vars(VarLocns, Code) -->
+	{ assoc_list__values(VarLocns, Lvals) },
+	{ code_util__max_mentioned_reg(Lvals, MaxReg) },
+	var_locn__lock_regs(MaxReg, VarLocns),
+	var_locn__actually_place_vars(VarLocns, Code),
+	var_locn__unlock_regs.
+
+:- pred var_locn__actually_place_vars(assoc_list(prog_var, lval)::in,
+	code_tree::out, var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__actually_place_vars([], empty) --> [].
+var_locn__actually_place_vars([Var - Lval | Rest], Code) -->
+	var_locn__place_var(Var, Lval, FirstCode),
+	var_locn__actually_place_vars(Rest, RestCode),
+	{ Code = tree(FirstCode, RestCode) }.
+
+var_locn__place_var(Var, Target, Code) -->
+	var_locn__actually_place_var(Var, Target, [], Code).
+
+:- pred var_locn__actually_place_var(prog_var::in, lval::in, list(lval)::in,
+	code_tree::out, var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__actually_place_var(Var, Target, ForbiddenLvals, Code) -->
+	var_locn__get_acquired(Acquired),
+	{ set__member(Target, Acquired) ->
+		error("var_locn__actually_place_var: target is acquired reg")
+	;
+		true
+	},
+	var_locn__get_var_state_map(VarStateMap0),
+	{ map__lookup(VarStateMap0, Var, State0) },
+	{ State0 = state(Lvals0, _, _, _, _) },
+	( { set__member(Target, Lvals0) } ->
+		{ Code = empty }
+	;
+		var_locn__free_up_lval(Target, [Var], ForbiddenLvals,
+			FreeCode),
+
+			% If Var's value is cached, Lvals0 must be empty.
+			% However, the cached value may simply be var(Other),
+			% and Other may already be in Target. However, it may
+			% also be in other lval, so we say we prefer the
+			% copy in Target.
+		var_locn__produce_var_maybe_expr(Var, yes(Target), Rval),
+		( { Rval = lval(SourceLval) } ->
+			var_locn__record_copy(SourceLval, Target)
+		;
+				% Record the clobbering of Target.
+			var_locn__record_clobbering(Target, [Var])
+		),
+
+			% Record that Var is now in Target.
+		var_locn__add_additional_lval_for_var(Var, Target),
+
+		( { Rval = lval(Target) } ->
+			{ AssignCode = empty }
+		;
+			var_locn__get_var_name(Var, VarName),
+			{ ForbiddenLvals = [] ->
+				string__append("Placing ", VarName, Msg)
+			;
+				string__int_to_string(
+					list__length(ForbiddenLvals),
+					LengthStr),
+				string__append_list(["Placing ", VarName,
+					" (depth ", LengthStr, ")"], Msg)
+			},
+			{ AssignCode = node([
+				assign(Target, Rval)
+					- Msg
+			]) }
+		),
+		{ Code = tree(FreeCode, AssignCode) }
+	).
+
+:- pred var_locn__record_clobbering(lval::in, list(prog_var)::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__record_clobbering(Target, Assigns) -->
+	var_locn__get_loc_var_map(LocVarMap1),
+	( { map__search(LocVarMap1, Target, DependentVarsSet) } ->
+		{ set__to_sorted_list(DependentVarsSet, DependentVars) },
+		{ map__delete(LocVarMap1, Target, LocVarMap) },
+		var_locn__set_loc_var_map(LocVarMap),
+
+		var_locn__get_var_state_map(VarStateMap2),
+		{ list__foldl(
+			var_locn__clobber_lval_in_var_state_map(Target,
+				Assigns),
+			DependentVars, VarStateMap2, VarStateMap) },
+		var_locn__set_var_state_map(VarStateMap)
+	;
+		[]
+	).
+
+% Make Lval available, i.e. make sure that the values of all variables
+% that are stored in an lval involving Lval are also available in places
+% not dependent on Lval. However, this requirement does not apply to the
+% variables (if any) in ToBeAssignedVars, since this lists the variable
+% that is to be assigned to Lval after it is freed up. (If ToBeAssignedVars
+% contains more than one variable, then those variables must be guaranteed
+% to be equal.) Nor does it apply to dead variables whose only use is as
+% components of AssignedVars.
+%
+% The point of this exception is to eliminate unnecessary shuffles. If
+% var_locn__place_var wants to put Var in Lval and Var is currently in (e.g)
+% field(Ptag, Lval, Offset), it will ask var_locn__free_up_lval to free up
+% Lval. However, if all the other variables affected variables are also
+% available independently of Lval, there should be no need to move the value
+% now in Lval somewhere else, since our caller can simply generate an
+% assignment such as Lval := field(Ptag, Lval, Offset).
+
+:- pred var_locn__free_up_lval(lval::in, list(prog_var)::in, list(lval)::in,
+	code_tree::out, var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__free_up_lval(Lval, ToBeAssignedVars, ForbiddenLvals, Code) -->
+	(
+		var_locn__get_loc_var_map(LocVarMap0),
+		{ map__search(LocVarMap0, Lval, AffectedVarSet) },
+		{ set__to_sorted_list(AffectedVarSet, AffectedVars) },
+		var_locn__get_var_state_map(VarStateMap0),
+		\+ { list__foldl(
+			var_locn__try_clobber_lval_in_var_state_map(
+				Lval, ToBeAssignedVars),
+			AffectedVars, VarStateMap0, _) }
+	->
+		var_locn__free_up_lval_with_copy(Lval, ToBeAssignedVars,
+			ForbiddenLvals, Code)
+	;
+		{ Code = empty }
+	).
+
+% If we must copy the value in Lval somewhere else to prevent it from being
+% lost when Lval overwritten, then we try to put it into a location where it
+% will be needed next. First we find a variable that is stored in Lval
+% directly, and not just in some location whose path includes Lval (the set
+% of all variables affected by the update of Lval is AffectedVarSet). Then we
+% look up where that variable (OccupyingVar) ought to be. If its desired
+% location is Lval itself, then the copy would be a null operation and would
+% not free up Lval, so in that case we get a spare register. If the desired
+% location is on the forbidden list, then we again get a spare register to
+% avoid infinite recursion (see the documentation of var_locn__free_up_lval
+% above). If the desired location (Pref) is neither Lval nor or on the
+% forbidden list, then we can possibly copy Lval there. If Pref is neither
+% in use nor locked, then moving Lval there requires just an assignment.
+% If Pref is locked, then it is possible that it is locked for use by
+% OccupyingVar. If this is so, we first recursively free up Pref, and then
+% move OccupyingVar there.
+
+:- pred var_locn__free_up_lval_with_copy(lval::in, list(prog_var)::in,
+	list(lval)::in, code_tree::out, var_locn_info::in, var_locn_info::out)
+	is det.
+
+var_locn__free_up_lval_with_copy(Lval, ToBeAssignedVars, ForbiddenLvals, Code)
+		-->
+	(
+		var_locn__get_loc_var_map(LocVarMap0),
+		{ map__search(LocVarMap0, Lval, AffectedVarSet) },
+		{ set__delete_list(AffectedVarSet, ToBeAssignedVars,
+			EffAffectedVarSet) },
+		{ set__to_sorted_list(EffAffectedVarSet, EffAffectedVars) },
+
+		var_locn__get_var_state_map(VarStateMap0),
+		(
+			{ var_locn__find_one_occupying_var(EffAffectedVars,
+				Lval, VarStateMap0, OccupyingVar,
+				OtherSources) }
+		->
+			{ MovedVar = OccupyingVar },
+			{ list__delete_all(EffAffectedVars, MovedVar,
+				OtherVars) },
+			list__foldl(var_locn__ensure_copies_are_present(
+				Lval, OtherSources), OtherVars)
+		;
+			{ EffAffectedVars = [MovedVar] }
+		),
+
+		{ CheckInUse = no },
+		var_locn__select_preferred_reg_or_stack(MovedVar, Pref,
+			CheckInUse),
+		{ \+ Pref = Lval },
+		{ \+ list__member(Pref, ForbiddenLvals) },
+		( \+ var_locn__lval_in_use(Pref) ->
+			[]
+		;
+				% The code generator assumes that values in
+				% stack slots don't get clobbered without an
+				% explicit assignment (via a place_var
+				% operation with a stack var as a target).
+			{ Pref = reg(r, RegNum) },
+			var_locn__reg_is_not_locked_for_var(RegNum, MovedVar)
+		)
+	->
+		var_locn__actually_place_var(MovedVar, Pref,
+			[Lval | ForbiddenLvals], Code)
+	;
+		var_locn__get_spare_reg(Target),
+		var_locn__record_copy(Lval, Target),
+		{ Code = node([
+			assign(Target, lval(Lval))
+				- "Freeing up the source lval"
+		]) }
+	).
+
+% Find a variable in the given list that is currently stored directly in Lval
+% (not just in some location who address includes Lval).
+
+:- pred var_locn__find_one_occupying_var(list(prog_var)::in, lval::in,
+	var_state_map::in, prog_var::out, list(lval)::out) is semidet.
+
+var_locn__find_one_occupying_var([Var | Vars], Lval, VarStateMap, OccupyingVar,
+		OtherSources) :-
+	map__lookup(VarStateMap, Var, State),
+	State = state(LvalSet, _, _, _, _),
+	( set__member(Lval, LvalSet) ->
+		OccupyingVar = Var,
+		set__delete(LvalSet, Lval, OtherSourceSet),
+		set__to_sorted_list(OtherSourceSet, OtherSources)
+	;
+		var_locn__find_one_occupying_var(Vars, Lval, VarStateMap,
+			OccupyingVar, OtherSources)
+	).
+
+:- pred var_locn__ensure_copies_are_present(lval::in, list(lval)::in,
+	prog_var::in, var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__ensure_copies_are_present(OneSource, OtherSources, Var) -->
+	var_locn__get_var_state_map(VarStateMap0),
+	{ map__lookup(VarStateMap0, Var, State0) },
+	{ State0 = state(LvalSet0, MaybeConstRval, MaybeExprRval,
+		Using, DeadOrAlive) },
+	{ set__to_sorted_list(LvalSet0, Lvals0) },
+	{ list__foldl(var_locn__ensure_copies_are_present_lval(
+		OtherSources, OneSource), Lvals0, LvalSet0, LvalSet) },
+	{ State = state(LvalSet, MaybeConstRval, MaybeExprRval,
+		Using, DeadOrAlive) },
+	{ map__det_update(VarStateMap0, Var, State, VarStateMap) },
+	var_locn__set_var_state_map(VarStateMap),
+
+	var_locn__get_loc_var_map(LocVarMap0),
+	{ var_locn__record_change_in_root_dependencies(LvalSet0, LvalSet, Var,
+		LocVarMap0, LocVarMap) },
+	var_locn__set_loc_var_map(LocVarMap).
+
+:- pred var_locn__ensure_copies_are_present_lval(list(lval)::in, lval::in,
+	lval::in, set(lval)::in, set(lval)::out) is det.
+
+var_locn__ensure_copies_are_present_lval([], _, _, LvalSet, LvalSet).
+var_locn__ensure_copies_are_present_lval([OtherSource | OtherSources],
+		OneSource, Lval, LvalSet0, LvalSet) :-
+	SubstLval = var_locn__substitute_lval_in_lval(OneSource, OtherSource,
+		Lval),
+	set__insert(LvalSet0, SubstLval, LvalSet1),
+	var_locn__ensure_copies_are_present_lval(OtherSources,
+		OneSource, Lval, LvalSet1, LvalSet).
+
+%----------------------------------------------------------------------------%
+
+% Record the effect of the assignment New := Old on the state of all the
+% affected variables.
+%
+% We find the set of affected variables by finding all the root lvals in
+% New and Old, and finding all the variables that depend on them. This
+% requires significant numbers of term traversals and lookup operations.
+% We could eliminate this cost by considering *all* variables to be affected.
+% Even though it would obviously call record_copy_for_var on more variables,
+% this may be faster overall. The reason why we don't do that is that
+% its worst case behavior can be pretty bad.
+
+:- pred var_locn__record_copy(lval::in, lval::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__record_copy(Old, New) -->
+	{ require(var_locn__is_root_lval(New),
+		"var_locn__record_copy: non-root New lval") },
+	var_locn__get_var_state_map(VarStateMap0),
+	var_locn__get_loc_var_map(LocVarMap0),
+	{ set__list_to_set([Old, New], AssignSet) },
+	{ var_locn__get_var_set_roots(AssignSet, NoDupRootLvals) },
+		% Convert the list of root lvals to the list of sets of
+		% affected vars; if a root lval is not in LocVarMap0,
+		% then it does not affect any variables.
+	{ list__filter_map(map__search(LocVarMap0), NoDupRootLvals,
+		AffectedVarSets) },
+		% Take the union of the list of sets of affected vars.
+	{ list__foldl(set__union, AffectedVarSets,
+		set__init, AffectedVarSet) },
+		% Convert the union set to a list of affected vars.
+	{ set__to_sorted_list(AffectedVarSet, AffectedVars) },
+	{ list__foldl2(var_locn__record_copy_for_var(Old, New),
+		AffectedVars, VarStateMap0, VarStateMap,
+		LocVarMap0, LocVarMap) },
+	var_locn__set_loc_var_map(LocVarMap),
+	var_locn__set_var_state_map(VarStateMap).
+
+% Record the effect of the assignment New := Old on the state of the given
+% variable.
+%
+% The main complication is that New and Old are not necessarily independent:
+% it is possible e.g. for New to be r1 and Old to be field(0, r1, 2).
+% This is why we perform the update in three steps.
+%
+% 1	For each lval in original LvalSet that contains Old, we add an
+%	additional lval in which Old is replaced by a unique Token lval
+%	(which cannot be a component of any legitimate lval). The Token
+%	represents the value being assigned, and prevents us from forgetting
+%	the path to the original value of Var from Old during step 2.
+%
+% 2	We delete from the set generated by step 1 all lvals that depend
+%	on New, to reflect the fact that New no longer contains what it
+%	used to contain.
+%
+% 3	We substitute New for all occurrences of Token, to reflect the fact
+%	that the assigned value is now in New.
+%
+% For example, with New and Old being as above and LvalSet0 being the set
+% { r5, field(3, field(0, r1, 2), 4) }:
+%
+% -	Step 1 will set LvalSet1 to { r5, field(3, Token, 4) }, and LvalSet2
+% 	to { r5, field(3, field(0, r1, 2), 4), field(3, Token, 4) }.
+%
+% -	Step 2 will set LvalSet3 { r5, field(3, Token, 4) }.
+%
+% -	Step 3 will set LvalSet { r5, field(3, r1, 4) }.
+%
+% The reason why we don't need to modify the MaybeExprRval field in the
+% variable state is that the only lvals these fields can refer to are
+% of the form var(_).
+
+:- pred var_locn__record_copy_for_var(lval::in, lval::in, prog_var::in,
+	var_state_map::in, var_state_map::out,
+	loc_var_map::in, loc_var_map::out) is det.
+
+var_locn__record_copy_for_var(Old, New, Var,
+		VarStateMap0, VarStateMap, LocVarMap0, LocVarMap) :-
+	map__lookup(VarStateMap0, Var, State0),
+	State0 = state(LvalSet0, MaybeConstRval, MaybeExprRval,
+		Using, DeadOrAlive),
+	Token = reg(r, -42),
+	LvalSet1 = set__map(var_locn__substitute_lval_in_lval(Old, Token),
+		LvalSet0),
+	set__union(LvalSet0, LvalSet1, LvalSet2),
+	LvalSet3 = set__filter(var_locn__lval_does_not_support_lval(New),
+		LvalSet2),
+	LvalSet = set__map(var_locn__substitute_lval_in_lval(Token, New),
+		LvalSet3),
+	State = state(LvalSet, MaybeConstRval, MaybeExprRval,
+		Using, DeadOrAlive),
+	require(var_locn__nonempty_state(State),
+		"var_locn__record_copy_for_var: empty state"),
+	map__det_update(VarStateMap0, Var, State, VarStateMap),
+
+	var_locn__record_change_in_root_dependencies(LvalSet0, LvalSet, Var,
+		LocVarMap0, LocVarMap).
+
+:- pred var_locn__record_change_in_root_dependencies(set(lval)::in,
+	set(lval)::in, prog_var::in, loc_var_map::in, loc_var_map::out) is det.
+
+var_locn__record_change_in_root_dependencies(OldLvalSet, NewLvalSet, Var,
+		LocVarMap0, LocVarMap) :-
+	var_locn__get_var_set_roots(OldLvalSet, OldRootLvals),
+	var_locn__get_var_set_roots(NewLvalSet, NewRootLvals),
+	set__list_to_set(OldRootLvals, OldRootLvalSet),
+	set__list_to_set(NewRootLvals, NewRootLvalSet),
+	set__difference(NewRootLvalSet, OldRootLvalSet, InsertSet),
+	set__difference(OldRootLvalSet, NewRootLvalSet, DeleteSet),
+	set__to_sorted_list(InsertSet, Inserts),
+	set__to_sorted_list(DeleteSet, Deletes),
+	list__foldl(var_locn__make_var_depend_on_root_lval(Var),
+		Inserts, LocVarMap0, LocVarMap1),
+	list__foldl(var_locn__make_var_not_depend_on_root_lval(Var),
+		Deletes, LocVarMap1, LocVarMap).
+
+:- func var_locn__substitute_lval_in_lval(lval, lval, lval) = lval.
+
+var_locn__substitute_lval_in_lval(Old, New, Lval0) = Lval :-
+	exprn_aux__substitute_lval_in_lval(Old, New, Lval0, Lval).
+
+%----------------------------------------------------------------------------%
+
+% Var has become dead. If there are no expression that depend on its value,
+% delete the record of its state, thus freeing up the resources it has
+% tied down: the locations it occupies, or the variables whose values its own
+% expression refers to. If there *are* expressions that depend on its value,
+% merely update the state of the variable to say that it is dead, which means
+% that its resources will be freed when the last reference to its value is
+% deleted.
+%
+% If FirstTime = yes, then as a consistency check we insist on Var being alive;
+% if FirstTime = no, then it is possible that this predicate has already been
+% called for Var.
+
+var_locn__var_becomes_dead(Var, FirstTime) -->
+	var_locn__get_var_state_map(VarStateMap0),
+	( { map__search(VarStateMap0, Var, State0) } ->
+		{ State0 = state(Lvals, MaybeConstRval, MaybeExprRval,
+			Using, DeadOrAlive0) },
+		( { DeadOrAlive0 = dead } ->
+			{ require(unify(FirstTime, no),
+				"var_locn__var_becomes_dead: already dead") }
+		;
+			[]
+		),
+		( { set__empty(Using) } ->
+			{ map__det_remove(VarStateMap0, Var, _, VarStateMap) },
+			var_locn__set_var_state_map(VarStateMap),
+
+			var_locn__get_loc_var_map(LocVarMap0),
+			{ var_locn__get_var_set_roots(Lvals, NoDupRootLvals) },
+			{ list__foldl(
+				var_locn__make_var_not_depend_on_root_lval(
+					Var),
+				NoDupRootLvals, LocVarMap0, LocVarMap) },
+			var_locn__set_loc_var_map(LocVarMap),
+
+			var_locn__remove_use_refs(MaybeExprRval, Var)
+		;
+			{ State = state(Lvals, MaybeConstRval, MaybeExprRval,
+				Using, dead) },
+			{ map__det_update(VarStateMap0, Var, State,
+				VarStateMap) },
+			var_locn__set_var_state_map(VarStateMap)
+		)
+	;
+		{ require(unify(FirstTime, no),
+			"var_locn__var_becomes_dead: premature deletion") }
+	).
+
+% Given a set of lvals, return the set of root lvals among them and inside
+% them.
+
+:- pred var_locn__get_var_set_roots(set(lval)::in, list(lval)::out) is det.
+
+var_locn__get_var_set_roots(Lvals, NoDupRootLvals) :-
+	set__to_sorted_list(Lvals, LvalList),
+	code_util__lvals_in_lvals(LvalList, ContainedLvals),
+	list__append(LvalList, ContainedLvals, AllLvals),
+	list__filter(var_locn__is_root_lval, AllLvals, RootLvals),
+	list__sort_and_remove_dups(RootLvals, NoDupRootLvals).
+
+%----------------------------------------------------------------------------%
+
+% Select the cheapest way to refer to the value of the variable.
+
+:- pred var_locn__select_expr_for_var(prog_var::in, var_state_map::in,
+	maybe(lval)::in, rval::out) is det.
+
+var_locn__select_expr_for_var(Var, VarStateMap, MaybePrefer, Rval) :-
+	map__lookup(VarStateMap, Var, State),
+	State = state(Lvals, MaybeConstRval, MaybeExprRval, _, _),
+	set__to_sorted_list(Lvals, LvalsList),
+	(
+		MaybePrefer = yes(Prefer),
+		list__member(Prefer, LvalsList)
+	->
+		Rval = lval(Prefer)
+	;
+		var_locn__maybe_select_lval_or_rval(LvalsList, MaybeConstRval,
+			Rval1)
+	->
+		Rval = Rval1
+	;
+		MaybeExprRval = yes(ExprRval)
+	->
+		var_locn__materialize_vars_in_rval(ExprRval, VarStateMap,
+			MaybePrefer, Rval)
+	;
+		error("var_locn__select_expr_for_var: no source")
+	).
+
+% From the given list of lvals, select the cheapest one to use.
+
+:- pred var_locn__select_lval(list(lval)::in, lval::out) is det.
+
+var_locn__select_lval(Lvals, Lval) :-
+	( var_locn__select_reg_lval(Lvals, Lval1) ->
+		Lval = Lval1
+	; var_locn__select_stack_lval(Lvals, Lval2) ->
+		Lval = Lval2
+	; var_locn__select_cheapest_lval(Lvals, Lval3) ->
+		Lval = Lval3
+	;
+		error("var_locn__select_lval: nothing to select")
+	).
+
+% From the given list of lvals and maybe a constant rval, select the cheapest
+% one to use.
+
+:- pred var_locn__select_lval_or_rval(list(lval)::in, maybe(rval)::in,
+	rval::out) is det.
+
+var_locn__select_lval_or_rval(Lvals, MaybeConstRval, Rval) :-
+	( var_locn__maybe_select_lval_or_rval(Lvals, MaybeConstRval, Rval1) ->
+		Rval = Rval1
+	;
+		error("var_locn__select_lval_or_rval: nothing to select")
+	).
+
+:- pred var_locn__maybe_select_lval_or_rval(list(lval)::in, maybe(rval)::in,
+	rval::out) is semidet.
+
+var_locn__maybe_select_lval_or_rval(Lvals, MaybeConstRval, Rval) :-
+	( var_locn__select_reg_lval(Lvals, Lval1) ->
+		Rval = lval(Lval1)
+	; var_locn__select_stack_lval(Lvals, Lval2) ->
+		Rval = lval(Lval2)
+	; MaybeConstRval = yes(ConstRval) ->
+		Rval = ConstRval
+	; var_locn__select_cheapest_lval(Lvals, Lval3) ->
+		Rval = lval(Lval3)
+	;
+		fail
+	).
+
+:- pred var_locn__select_reg_lval(list(lval)::in, lval::out) is semidet.
+
+var_locn__select_reg_lval([Lval0 | Lvals0], Lval) :-
+	( Lval0 = reg(_, _) ->
+		Lval = Lval0
+	;
+		var_locn__select_reg_lval(Lvals0, Lval)
+	).
+
+:- pred var_locn__select_stack_lval(list(lval)::in, lval::out) is semidet.
+
+var_locn__select_stack_lval([Lval0 | Lvals0], Lval) :-
+	( ( Lval0 = stackvar(_) ; Lval0 = framevar(_)) ->
+		Lval = Lval0
+	;
+		var_locn__select_stack_lval(Lvals0, Lval)
+	).
+
+:- pred var_locn__select_reg_or_stack_lval(list(lval)::in, lval::out)
+	is semidet.
+
+var_locn__select_reg_or_stack_lval([Lval0 | Lvals0], Lval) :-
+	(
+		( Lval0 = reg(_, _)
+		; Lval0 = stackvar(_)
+		; Lval0 = framevar(_)
+		)
+	->
+		Lval = Lval0
+	;
+		var_locn__select_reg_or_stack_lval(Lvals0, Lval)
+	).
+
+:- pred var_locn__select_cheapest_lval(list(lval)::in, lval::out) is semidet.
+
+	% From the given list of lvals, select the cheapest one to use.
+	% Since none of the lvals will be a register or stack variable,
+	% in almost all cases, the given list will be a singleton.
+var_locn__select_cheapest_lval([Lval | _], Lval).
+
+%----------------------------------------------------------------------------%
+
+:- pred var_locn__select_preferred_reg(prog_var::in, lval::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__select_preferred_reg(Var, Lval) -->
+	var_locn__select_preferred_reg(Var, Lval, yes).
+
+% Select the register into which Var should be put. If the follow_vars map
+% maps Var to a register, then select that register, unless it is already in
+% use, and CheckInUse = yes.
+
+:- pred var_locn__select_preferred_reg(prog_var::in, lval::out, bool::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__select_preferred_reg(Var, Lval, CheckInUse) -->
+	var_locn__get_follow_var_map(FollowVarMap),
+	(
+		{ map__search(FollowVarMap, Var, PrefLval) },
+		{ PrefLval = reg(_, _) }
+	->
+		(
+			{ real_lval(PrefLval) },
+			( { CheckInUse = yes } ->
+				\+ var_locn__lval_in_use(PrefLval)
+			;
+				[]
+			)
+		->
+			{ Lval = PrefLval }
+		;
+			var_locn__get_spare_reg(Lval)
+		)
+	;
+		var_locn__get_spare_reg(Lval)
+	).
+
+% Select the register or stack slot into which Var should be put. If the
+% follow_vars map maps Var to a register, then select that register,
+% unless it is already in use and CheckInUse = yes. If the follow_vars map
+% does not contain Var, then Var is not needed in a register in the near
+% future, and this we select Var's stack slot, unless it is in use and
+% CheckInUse = yes. If all else fails, we get spare, unused register.
+% (Note that if the follow_vars pass has not been run, then all follow vars
+% maps will be empty, which would cause this predicate to try to put far too
+% many things in stack slots. This is why the --no-lazy-code option implies
+% --follow-vars.)
+
+:- pred var_locn__select_preferred_reg_or_stack(prog_var::in, lval::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__select_preferred_reg_or_stack(Var, Lval) -->
+	var_locn__select_preferred_reg_or_stack(Var, Lval, yes).
+
+:- pred var_locn__select_preferred_reg_or_stack(prog_var::in, lval::out,
+	bool::in, var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__select_preferred_reg_or_stack(Var, Lval, CheckInUse) -->
+	var_locn__get_follow_var_map(FollowVarMap),
+	(
+		{ map__search(FollowVarMap, Var, PrefLval) },
+		{ PrefLval = reg(_, _) }
+	->
+		(
+			{ real_lval(PrefLval) },
+			( { CheckInUse = yes } ->
+				\+ var_locn__lval_in_use(PrefLval)
+			;
+				[]
+			)
+		->
+			{ Lval = PrefLval }
+		;
+			var_locn__get_spare_reg(Lval)
+		)
+	;
+		(
+			var_locn__get_stack_slots(StackSlots),
+			{ map__search(StackSlots, Var, StackSlot) },
+			( { CheckInUse = yes } ->
+				\+ var_locn__lval_in_use(StackSlot)
+			;
+				[]
+			)
+		->
+			{ Lval = StackSlot }
+		;
+			var_locn__get_spare_reg(Lval)
+		)
+	).
+
+:- pred real_lval(lval::in) is semidet.
+
+real_lval(Lval) :-
+	\+ (
+		Lval = reg(_, N),
+		N < 1
+	).
+
+%----------------------------------------------------------------------------%
+
+% Get a register that is not in use. We start the search at the next register
+% that is needed for the next call.
+
+:- pred var_locn__get_spare_reg(lval::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__get_spare_reg(Lval) -->
+	var_locn__get_next_non_reserved(NextNonReserved),
+	var_locn__get_spare_reg_2(NextNonReserved, Lval).
+
+:- pred var_locn__get_spare_reg_2(int::in, lval::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__get_spare_reg_2(N0, Lval) -->
+	( var_locn__lval_in_use(reg(r, N0)) ->
+		var_locn__get_spare_reg_2(N0 + 1, Lval)
+	;
+		{ Lval = reg(r, N0) }
+	).
+
+% Succeeds if Lval is currently in use or locked.
+
+var_locn__lval_in_use(Lval) -->
+	var_locn__get_loc_var_map(LocVarMap),
+	var_locn__get_acquired(Acquired),
+	var_locn__get_locked(Locked),
+	{
+		map__search(LocVarMap, Lval, UsingVars),
+		\+ set__empty(UsingVars)
+	;
+		set__member(Lval, Acquired)
+	;
+		Lval = reg(r, N),
+		N =< Locked
+	}.
+
+% Succeeds if Var may be stored in Reg, possibly after copying its contents
+% somewhere else. This requires Reg to be either not locked, or if it is
+% locked, to be locked for Var.
+
+:- pred var_locn__reg_is_not_locked_for_var(int::in, prog_var::in,
+	var_locn_info::in, var_locn_info::out) is semidet.
+
+var_locn__reg_is_not_locked_for_var(RegNum, Var) -->
+	var_locn__get_acquired(Acquired),
+	var_locn__get_locked(Locked),
+	var_locn__get_exceptions(Exceptions),
+	{
+		Reg = reg(r, RegNum),
+		\+ set__member(Reg, Acquired),
+		RegNum =< Locked =>
+		(
+			assoc_list__search(Exceptions, Var, VarExcpLval),
+			VarExcpLval = Reg
+		)
+	}.
+
+%----------------------------------------------------------------------------%
+
+var_locn__acquire_reg(Lval) -->
+	var_locn__get_spare_reg(Lval),
+	var_locn__get_acquired(Acquired0),
+	{ set__insert(Acquired0, Lval, Acquired) },
+	var_locn__set_acquired(Acquired).
+
+var_locn__acquire_reg_require_given(Lval) -->
+	( var_locn__lval_in_use(Lval) ->
+		{ error("var_locn__acquire_reg_require_given: lval in use") }
+	;
+		[]
+	),
+	var_locn__get_acquired(Acquired0),
+	{ set__insert(Acquired0, Lval, Acquired) },
+	var_locn__set_acquired(Acquired).
+
+var_locn__acquire_reg_prefer_given(Pref, Lval) -->
+	{ PrefLval = reg(r, Pref) },
+	( var_locn__lval_in_use(PrefLval) ->
+		var_locn__get_spare_reg(Lval)
+	;
+		{ Lval = PrefLval }
+	),
+	var_locn__get_acquired(Acquired0),
+	{ set__insert(Acquired0, Lval, Acquired) },
+	var_locn__set_acquired(Acquired).
+
+var_locn__acquire_reg_start_at_given(Start, Lval) -->
+	{ StartLval = reg(r, Start) },
+	( var_locn__lval_in_use(StartLval) ->
+		var_locn__acquire_reg_start_at_given(Start + 1, Lval)
+	;
+		{ Lval = StartLval },
+		var_locn__get_acquired(Acquired0),
+		{ set__insert(Acquired0, Lval, Acquired) },
+		var_locn__set_acquired(Acquired)
+	).
+
+var_locn__release_reg(Lval) -->
+	var_locn__get_acquired(Acquired0),
+	( { set__member(Lval, Acquired0) } ->
+		{ set__delete(Acquired0, Lval, Acquired) },
+		var_locn__set_acquired(Acquired)
+	;
+		{ error("var_locn__release_reg: unacquired reg") }
+	).
+
+%----------------------------------------------------------------------------%
+
+var_locn__lock_regs(N, Exceptions) -->
+	var_locn__set_locked(N),
+	var_locn__set_exceptions(Exceptions).
+
+var_locn__unlock_regs -->
+	var_locn__set_locked(0),
+	var_locn__set_exceptions([]).
+
+%----------------------------------------------------------------------------%
+
+var_locn__max_reg_in_use(VarLocnInfo, Max) :-
+	var_locn__get_loc_var_map(LocVarMap, VarLocnInfo, _),
+	map__keys(LocVarMap, VarLocs),
+	code_util__max_mentioned_reg(VarLocs, Max1),
+	var_locn__get_acquired(Acquired, VarLocnInfo, _),
+	set__to_sorted_list(Acquired, AcquiredList),
+	code_util__max_mentioned_reg(AcquiredList, Max2),
+	int__max(Max1, Max2, Max).
+
+%----------------------------------------------------------------------------%
+
+% var_locn__expr_is_constant(Rval0, VarStateMap, ExprnOpts, Rval)
+% Check if Rval0 is a constant rval, after substituting the values of the
+% variables inside it. Returns the substituted, ground rval in Rval.
+% Note that this predicate is similar to code_exprn__expr_is_constant,
+% but of courses its own version of the variable state data structure.
+
+:- pred var_locn__expr_is_constant(rval::in, var_state_map::in, exprn_opts::in,
+	rval::out) is semidet.
+
+var_locn__expr_is_constant(const(Const), _, ExprnOpts, const(Const)) :-
+	exprn_aux__const_is_constant(Const, ExprnOpts, yes).
+
+var_locn__expr_is_constant(unop(Op, Expr0), VarStateMap, ExprnOpts,
+		unop(Op, Expr)) :-
+	var_locn__expr_is_constant(Expr0, VarStateMap, ExprnOpts, Expr).
+
+var_locn__expr_is_constant(binop(Op, Expr1, Expr2), VarStateMap, ExprnOpts,
+		binop(Op, Expr3, Expr4)) :-
+	var_locn__expr_is_constant(Expr1, VarStateMap, ExprnOpts, Expr3),
+	var_locn__expr_is_constant(Expr2, VarStateMap, ExprnOpts, Expr4).
+
+var_locn__expr_is_constant(mkword(Tag, Expr0), VarStateMap, ExprnOpts,
+		mkword(Tag, Expr)) :-
+	var_locn__expr_is_constant(Expr0, VarStateMap, ExprnOpts, Expr).
+
+var_locn__expr_is_constant(create(Tag, Args0, ArgTypes, StatDyn,
+		Label, Msg, Reuse),
+		VarStateMap, ExprnOpts, NewRval) :-
+	Reuse = no,
+	( StatDyn = must_be_static ->
+		NewRval = create(Tag, Args0, ArgTypes, StatDyn,
+			Label, Msg, Reuse)
+	;
+		ExprnOpts = nlg_asm_sgt_ubf(_, _, StaticGroundTerms, _),
+		StaticGroundTerms = yes,
+		var_locn__args_are_constant(Args0, VarStateMap, ExprnOpts,
+			Args),
+		NewRval = create(Tag, Args, ArgTypes, StatDyn,
+			Label, Msg, Reuse)
+	).
+
+var_locn__expr_is_constant(var(Var), VarStateMap, ExprnOpts, Rval) :-
+	map__search(VarStateMap, Var, State),
+	State = state(_, yes(Rval), _, _, _),
+	require(var_locn__expr_is_constant(Rval, VarStateMap, ExprnOpts, _),
+		"non-constant rval in variable state").
+
+:- pred var_locn__args_are_constant(list(maybe(rval))::in, var_state_map::in,
+	exprn_opts::in, list(maybe(rval))::out) is semidet.
+
+var_locn__args_are_constant([], _VarStateMap, _ExprnOpts, []).
+var_locn__args_are_constant([Arg0 | Args0], VarStateMap, ExprnOpts,
+		[Arg | Args]) :-
+	% if any of the fields are 'no' then we cannot treat the
+	% term as a constant.
+	Arg0 = yes(Rval0),
+	var_locn__expr_is_constant(Rval0, VarStateMap, ExprnOpts, Rval),
+	Arg = yes(Rval),
+	var_locn__args_are_constant(Args0, VarStateMap, ExprnOpts, Args).
+
+%----------------------------------------------------------------------------%
+
+% Lval is Lval0 with all variables in Lval0 replaced by their values.
+
+var_locn__materialize_vars_in_lval(Lval0, Lval) -->
+	var_locn__get_var_state_map(VarStateMap),
+	{ var_locn__materialize_vars_in_lval(Lval0, VarStateMap, Lval) }.
+
+:- pred var_locn__materialize_vars_in_lval(lval::in, var_state_map::in,
+	lval::out) is det.
+
+var_locn__materialize_vars_in_lval(Lval0, VarStateMap, Lval) :-
+	(
+		Lval0 = reg(_, _),
+		Lval = Lval0
+	;
+		Lval0 = stackvar(_),
+		Lval = Lval0
+	;
+		Lval0 = framevar(_),
+		Lval = Lval0
+	;
+		Lval0 = succip,
+		Lval = Lval0
+	;
+		Lval0 = maxfr,
+		Lval = Lval0
+	;
+		Lval0 = curfr,
+		Lval = Lval0
+	;
+		Lval0 = hp,
+		Lval = Lval0
+	;
+		Lval0 = sp,
+		Lval = Lval0
+	;
+		Lval0 = succip(Rval0),
+		var_locn__materialize_vars_in_rval(Rval0, VarStateMap, no,
+			Rval),
+		Lval = succip(Rval)
+	;
+		Lval0 = redoip(Rval0),
+		var_locn__materialize_vars_in_rval(Rval0, VarStateMap, no,
+			Rval),
+		Lval = redoip(Rval)
+	;
+		Lval0 = succfr(Rval0),
+		var_locn__materialize_vars_in_rval(Rval0, VarStateMap, no,
+			Rval),
+		Lval = succfr(Rval)
+	;
+		Lval0 = redofr(Rval0),
+		var_locn__materialize_vars_in_rval(Rval0, VarStateMap, no,
+			Rval),
+		Lval = redofr(Rval)
+	;
+		Lval0 = prevfr(Rval0),
+		var_locn__materialize_vars_in_rval(Rval0, VarStateMap, no,
+			Rval),
+		Lval = prevfr(Rval)
+	;
+		Lval0 = mem_ref(Rval0),
+		var_locn__materialize_vars_in_rval(Rval0, VarStateMap, no,
+			Rval),
+		Lval = mem_ref(Rval)
+	;
+		Lval0 = field(Tag, RvalA0, RvalB0),
+		var_locn__materialize_vars_in_rval(RvalA0, VarStateMap, no,
+			RvalA),
+		var_locn__materialize_vars_in_rval(RvalB0, VarStateMap, no,
+			RvalB),
+		Lval = field(Tag, RvalA, RvalB)
+	;
+		Lval0 = temp(_, _),
+		error("var_locn__materialize_vars_in_lval: temp")
+	;
+		Lval0 = lvar(_),
+		error("var_locn__materialize_vars_in_lval: lvar")
+	).
+
+% Rval is Rval0 with all variables in Rval0 replaced by their values.
+
+:- pred var_locn__materialize_vars_in_rval(rval::in, var_state_map::in,
+	maybe(lval)::in, rval::out) is det.
+
+var_locn__materialize_vars_in_rval(Rval0, VarStateMap, MaybePrefer, Rval) :-
+	(
+		Rval0 = lval(Lval0),
+		var_locn__materialize_vars_in_lval(Lval0, VarStateMap, Lval),
+		Rval = lval(Lval)
+	;
+		Rval0 = mkword(Tag, SubRval0),
+		var_locn__materialize_vars_in_rval(SubRval0, VarStateMap,
+			no, SubRval),
+		Rval = mkword(Tag, SubRval)
+	;
+		Rval0 = unop(Unop, SubRval0),
+		var_locn__materialize_vars_in_rval(SubRval0, VarStateMap,
+			no, SubRval),
+		Rval = unop(Unop, SubRval)
+	;
+		Rval0 = binop(Binop, SubRvalA0, SubRvalB0),
+		var_locn__materialize_vars_in_rval(SubRvalA0, VarStateMap,
+			no, SubRvalA),
+		var_locn__materialize_vars_in_rval(SubRvalB0, VarStateMap,
+			no, SubRvalB),
+		Rval = binop(Binop, SubRvalA, SubRvalB)
+	;
+		Rval0 = const(_),
+		Rval = Rval0
+	;
+		Rval0 = mem_addr(_),
+		Rval = Rval0
+	;
+			% If we get here, the cell must be a constant.
+		Rval0 = create(_, _, _, _, _, _, _),
+		Rval = Rval0
+	;
+		Rval0 = var(Var),
+		var_locn__select_expr_for_var(Var, VarStateMap, MaybePrefer,
+			Rval)
+	).
+
+%----------------------------------------------------------------------------%
+
+% Update LocVarMap0 to reflect the dependence of Var on all the root lvals
+% among Lvals or contained inside Lvals.
+
+:- pred var_locn__make_var_depend_on_lvals_roots(prog_var::in,
+	set(lval)::in, loc_var_map::in, loc_var_map::out) is det.
+
+var_locn__make_var_depend_on_lvals_roots(Var, Lvals,
+		LocVarMap0, LocVarMap) :-
+	var_locn__get_var_set_roots(Lvals, NoDupRootLvals),
+	list__foldl(var_locn__make_var_depend_on_root_lval(Var),
+		NoDupRootLvals, LocVarMap0, LocVarMap).
+
+:- pred var_locn__make_var_depend_on_lval_roots(prog_var::in,
+	lval::in, loc_var_map::in, loc_var_map::out) is det.
+
+var_locn__make_var_depend_on_lval_roots(Var, Lval, LocVarMap0, LocVarMap) :-
+	set__singleton_set(Lvals, Lval),
+	var_locn__make_var_depend_on_lvals_roots(Var, Lvals,
+		LocVarMap0, LocVarMap).
+
+:- pred var_locn__make_var_depend_on_root_lval(prog_var::in, lval::in,
+	loc_var_map::in, loc_var_map::out) is det.
+
+var_locn__make_var_depend_on_root_lval(Var, Lval, LocVarMap0, LocVarMap) :-
+	require(var_locn__is_root_lval(Lval),
+		"var_locn__make_var_depend_on_root_lval: non-root lval"),
+	( map__search(LocVarMap0, Lval, Vars0) ->
+		set__insert(Vars0, Var, Vars),
+		map__det_update(LocVarMap0, Lval, Vars, LocVarMap)
+	;
+		set__singleton_set(Vars, Var),
+		map__det_insert(LocVarMap0, Lval, Vars, LocVarMap)
+	).
+
+% Update LocVarMap0 to reflect that Var is no longer dependent on the root lval
+% Lval.
+
+:- pred var_locn__make_var_not_depend_on_root_lval(prog_var::in, lval::in,
+	loc_var_map::in, loc_var_map::out) is det.
+
+var_locn__make_var_not_depend_on_root_lval(Var, Lval, LocVarMap0, LocVarMap) :-
+	require(var_locn__is_root_lval(Lval),
+		"var_locn__make_var_depend_on_root_lval: non-root lval"),
+	( map__search(LocVarMap0, Lval, Vars0) ->
+		set__delete(Vars0, Var, Vars),
+		( set__empty(Vars) ->
+			map__det_remove(LocVarMap0, Lval, _, LocVarMap)
+		;
+			map__det_update(LocVarMap0, Lval, Vars, LocVarMap)
+		)
+	;
+		error("var_locn__make_var_not_depend_on_root_lval: no record")
+	).
+
+:- pred var_locn__is_root_lval(lval::in) is semidet.
+
+var_locn__is_root_lval(reg(r, _)).
+var_locn__is_root_lval(stackvar(_)).
+var_locn__is_root_lval(framevar(_)).
+
+%----------------------------------------------------------------------------%
+
+:- type dep_search_lval
+	--->	all_regs
+	;	specific_reg_or_stack(lval).
+
+:- pred var_locn__lval_does_not_support_lval(lval::in, lval::in) is semidet.
+
+var_locn__lval_does_not_support_lval(Lval1, Lval2) :-
+	\+ var_locn__lval_depends_on_search_lval(Lval2,
+		specific_reg_or_stack(Lval1)).
+
+:- pred var_locn__rval_depends_on_search_lval(rval::in, dep_search_lval::in)
+	is semidet.
+
+var_locn__rval_depends_on_search_lval(lval(Lval), SearchLval) :-
+	var_locn__lval_depends_on_search_lval(Lval, SearchLval).
+var_locn__rval_depends_on_search_lval(var(_Var), _SearchLval) :-
+	error("var_locn__rval_depends_on_search_lval: var").
+var_locn__rval_depends_on_search_lval(create(_, Rvals, _, _, _, _, Reuse),
+		SearchLval) :-
+	var_locn__args_depend_on_search_lval([Reuse | Rvals], SearchLval).
+var_locn__rval_depends_on_search_lval(mkword(_Tag, Rval), SearchLval) :-
+	var_locn__rval_depends_on_search_lval(Rval, SearchLval).
+var_locn__rval_depends_on_search_lval(const(_Const), _SearchLval) :-
+	fail.
+var_locn__rval_depends_on_search_lval(unop(_Op, Rval), SearchLval) :-
+	var_locn__rval_depends_on_search_lval(Rval, SearchLval).
+var_locn__rval_depends_on_search_lval(binop(_Op, Rval0, Rval1), SearchLval) :-
+	(
+		var_locn__rval_depends_on_search_lval(Rval0, SearchLval)
+	;
+		var_locn__rval_depends_on_search_lval(Rval1, SearchLval)
+	).
+
+:- pred var_locn__lval_depends_on_search_lval(lval::in, dep_search_lval::in)
+	is semidet.
+
+var_locn__lval_depends_on_search_lval(reg(Type, Num), SearchLval) :-
+	(
+		SearchLval = all_regs
+	;
+		SearchLval = specific_reg_or_stack(Lval),
+		Lval = reg(Type, Num)
+	).
+var_locn__lval_depends_on_search_lval(stackvar(Num), SearchLval) :-
+	SearchLval = specific_reg_or_stack(Lval),
+	Lval = stackvar(Num).
+var_locn__lval_depends_on_search_lval(framevar(Num), SearchLval) :-
+	SearchLval = specific_reg_or_stack(Lval),
+	Lval = framevar(Num).
+var_locn__lval_depends_on_search_lval(lvar(_Var), _SearchLval) :-
+	error("var_locn__lval_depends_on_search_lval: lvar").
+var_locn__lval_depends_on_search_lval(field(_Tag, Rval0, Rval1), SearchLval) :-
+	(
+		var_locn__rval_depends_on_search_lval(Rval0, SearchLval)
+	;
+		var_locn__rval_depends_on_search_lval(Rval1, SearchLval)
+	).
+
+:- pred var_locn__args_depend_on_search_lval(list(maybe(rval))::in,
+	dep_search_lval::in) is semidet.
+
+var_locn__args_depend_on_search_lval([], _SearchLval) :-
+	fail.
+var_locn__args_depend_on_search_lval([Arg | Args], SearchLval) :-
+	(
+		Arg = yes(Rval),
+		var_locn__rval_depends_on_search_lval(Rval, SearchLval)
+	;
+		var_locn__args_depend_on_search_lval(Args, SearchLval)
+	).
+
+%----------------------------------------------------------------------------%
+
+var_locn__set_follow_vars(follow_vars(FollowVarMap, NextNonReserved)) -->
+	var_locn__set_follow_var_map(FollowVarMap),
+	var_locn__set_next_non_reserved(NextNonReserved).
+
+%----------------------------------------------------------------------------%
+
+:- pred var_locn__get_var_name(prog_var::in, string::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__get_var_name(Var, Name) -->
+	var_locn__get_varset(Varset),
+	{ varset__lookup_name(Varset, Var, Name) }.
+
+%----------------------------------------------------------------------------%
+
+:- pred var_locn__nonempty_state(var_state::in) is semidet.
+
+var_locn__nonempty_state(State) :-
+	State = state(LvalSet, MaybeConstRval, MaybeExprRval, _, _),
+	( set__non_empty(LvalSet)
+	; MaybeConstRval = yes(_)
+	; MaybeExprRval = yes(_)
+	).
+
+%----------------------------------------------------------------------------%
+
+:- pred var_locn__get_varset(prog_varset::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__set_varset(prog_varset::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__get_exprn_opts(exprn_opts::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__set_follow_var_map(follow_vars_map::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__set_next_non_reserved(int::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__get_var_state_map(var_state_map::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__set_var_state_map(var_state_map::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__get_loc_var_map(loc_var_map::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__set_loc_var_map(loc_var_map::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__get_acquired(set(lval)::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__set_acquired(set(lval)::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__get_locked(int::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__set_locked(int::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__get_exceptions(assoc_list(prog_var, lval)::out,
+	var_locn_info::in, var_locn_info::out) is det.
+
+:- pred var_locn__set_exceptions(assoc_list(prog_var, lval)::in,
+	var_locn_info::in, var_locn_info::out) is det.
+
+var_locn__get_varset(VI^varset, VI, VI).
+var_locn__get_stack_slots(VI^stack_slots, VI, VI).
+var_locn__get_exprn_opts(VI^exprn_opts, VI, VI).
+var_locn__get_follow_var_map(VI^follow_vars_map, VI, VI).
+var_locn__get_next_non_reserved(VI^next_non_res, VI, VI).
+var_locn__get_var_state_map(VI^var_state_map, VI, VI).
+var_locn__get_loc_var_map(VI^loc_var_map, VI, VI).
+var_locn__get_acquired(VI^acquired, VI, VI).
+var_locn__get_locked(VI^locked, VI, VI).
+var_locn__get_exceptions(VI^exceptions, VI, VI).
+
+var_locn__set_varset(VS, VI, VI^varset := VS).
+var_locn__set_follow_var_map(FVM, VI, VI^follow_vars_map := FVM).
+var_locn__set_next_non_reserved(NNR, VI, VI^next_non_res := NNR).
+var_locn__set_var_state_map(VSM, VI, VI^var_state_map := VSM).
+var_locn__set_loc_var_map(LVM, VI, VI^loc_var_map := LVM).
+var_locn__set_acquired(A, VI, VI^acquired := A).
+var_locn__set_locked(L, VI, VI^locked := L).
+var_locn__set_exceptions(E, VI, VI^exceptions := E).
+
+%----------------------------------------------------------------------------%
--------------------------------------------------------------------------
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