for review: new method of handling failures, part 3 of 6
Zoltan Somogyi
zs at cs.mu.OZ.AU
Thu Jul 2 16:21:25 AEST 1998
Index: compiler/basic_block.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/basic_block.m,v
retrieving revision 1.5
diff -u -r1.5 basic_block.m
--- basic_block.m 1998/06/09 02:11:59 1.5
+++ basic_block.m 1998/06/29 08:18:22
@@ -160,7 +160,7 @@
;
Labels = []
).
-possible_targets(mkframe(_, _, _, _), []).
+possible_targets(mkframe(_, _), []).
possible_targets(modframe(_), []).
possible_targets(label(_), []).
possible_targets(goto(CodeAddr), Targets) :-
Index: compiler/call_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/call_gen.m,v
retrieving revision 1.122
diff -u -r1.122 call_gen.m
--- call_gen.m 1998/05/16 07:29:43 1.122
+++ call_gen.m 1998/05/17 07:06:55
@@ -37,25 +37,9 @@
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_det_builtin(pred_id, proc_id, list(var),
+:- pred call_gen__generate_builtin(code_model, pred_id, proc_id, list(var),
code_tree, code_info, code_info).
-:- mode call_gen__generate_det_builtin(in, in, in, out, in, out) is det.
-
-:- pred call_gen__generate_semidet_builtin(pred_id, proc_id, list(var),
- code_tree, code_info, code_info).
-:- mode call_gen__generate_semidet_builtin(in, in, in, out, in, out) is det.
-
-:- pred call_gen__generate_nondet_builtin(pred_id, proc_id, list(var),
- code_tree, code_info, code_info).
-:- mode call_gen__generate_nondet_builtin(in, in, in, out, in, out) is
- erroneous.
-
-/* DEAD CODE
-:- pred call_gen__generate_complicated_unify(var, var, uni_mode, can_fail,
- code_tree, code_info, code_info).
-:- mode call_gen__generate_complicated_unify(in, in, in, in, out, in, out)
- is det.
-*/
+:- mode call_gen__generate_builtin(in, in, in, in, out, in, out) is det.
:- pred call_gen__partition_args(assoc_list(var, arg_info),
list(var), list(var)).
@@ -100,17 +84,12 @@
% save possibly unknown variables on the stack as well
% if they may be needed on backtracking, and figure out the
% call model
- call_gen__prepare_for_call(CodeModel, FlushCode, CallModel, _),
+ call_gen__prepare_for_call(CodeModel, FlushCode, CallModel, _, _),
% move the input arguments to their registers
code_info__setup_call(ArgsInfos, caller, SetupCode),
- code_info__get_maybe_trace_info(MaybeTraceInfo),
- ( { MaybeTraceInfo = yes(TraceInfo) } ->
- { trace__prepare_for_call(TraceInfo, TraceCode) }
- ;
- { TraceCode = empty }
- ),
+ trace__prepare_for_call(TraceCode),
% figure out what locations are live at the call point,
% for use by the value numbering optimization
@@ -155,17 +134,17 @@
%---------------------------------------------------------------------------%
%
- % for a higher-order call,
+ % For a higher-order call,
% we split the arguments into inputs and outputs, put the inputs
% in the locations expected by do_call_<detism>_closure in
- % runtime/mercury_ho_call.c, generate the call to
- % do_call_<detism>_closure, and pick up the outputs from the
- % locations that we know runtime/mercury_ho_call.c leaves them in.
+ % runtime/mercury_ho_call.c, generate the call to that code,
+ % and pick up the outputs from the locations that we know
+ % the runtime system leaves them in.
%
- % lambda.m ensures that procedures which are directly
- % higher-order-called use the compact argument convertion,
- % so that runtime/mercury_ho_call.c doesn't have trouble
- % figuring out which registers the arguments go in.
+ % Lambda.m transforms the generated lambda predicates to
+ % make sure that all inputs come before all outputs, so that
+ % the code in the runtime system doesn't have trouble figuring out
+ % which registers the arguments go in.
%
call_gen__generate_higher_order_call(_OuterCodeModel, PredVar, Args, Types,
@@ -178,12 +157,11 @@
ArgInfos) },
{ assoc_list__from_corresponding_lists(Args, ArgInfos, ArgsInfos) },
{ call_gen__partition_args(ArgsInfos, InVars, OutVars) },
- code_info__succip_is_used,
{ set__list_to_set(OutVars, OutArgs) },
call_gen__save_variables(OutArgs, SaveCode),
call_gen__prepare_for_call(CodeModel, FlushCode, CallModel,
- RuntimeAddr),
+ DoHigherCall, _),
% place the immediate input arguments in registers
% starting at r4.
@@ -228,19 +206,13 @@
"Assign number of output arguments"
]) },
- code_info__get_maybe_trace_info(MaybeTraceInfo),
- ( { MaybeTraceInfo = yes(TraceInfo) } ->
- { trace__prepare_for_call(TraceInfo, TraceCode) }
- ;
- { TraceCode = empty }
- ),
-
+ trace__prepare_for_call(TraceCode),
code_info__get_next_label(ReturnLabel),
{ CallCode = node([
livevals(LiveVals)
- "",
- call(RuntimeAddr, label(ReturnLabel), OutLiveVals, CallModel)
- - "setup and call higher order pred",
+ call(DoHigherCall, label(ReturnLabel), OutLiveVals, CallModel)
+ - "Setup and call higher order pred",
label(ReturnLabel)
- "Continuation label"
]) },
@@ -263,16 +235,17 @@
%---------------------------------------------------------------------------%
%
- % for a class method call,
+ % For a class method call,
% we split the arguments into inputs and outputs, put the inputs
% in the locations expected by do_call_<detism>_class_method in
- % runtime/mercury_ho_call.c, generate the call to
- % do_call_<detism>_class_method, and pick up the outputs from the
- % locations that we know runtime/mercury_ho_call.c leaves them in.
+ % runtime/mercury_ho_call.c, generate the call to that code,
+ % and pick up the outputs from the locations that we know
+ % the runtime system leaves them in.
%
+
call_gen__generate_class_method_call(_OuterCodeModel, TCVar, MethodNum, Args,
Types, Modes, Det, GoalInfo, Code) -->
- { determinism_to_code_model(Det, InnerCodeModel) },
+ { determinism_to_code_model(Det, CodeModel) },
code_info__get_globals(Globals),
code_info__get_module_info(ModuleInfo),
@@ -282,40 +255,15 @@
;
{ error("Sorry, typeclasses with simple args_method not yet implemented") }
),
- { make_arg_infos(ArgsMethod, Types, Modes, InnerCodeModel, ModuleInfo,
+ { make_arg_infos(ArgsMethod, Types, Modes, CodeModel, ModuleInfo,
ArgInfo) },
{ assoc_list__from_corresponding_lists(Args, ArgInfo, ArgsAndArgInfo) },
{ call_gen__partition_args(ArgsAndArgInfo, InVars, OutVars) },
- call_gen__generate_class_method_call_2(InnerCodeModel, TCVar,
- MethodNum, InVars, OutVars, GoalInfo, Code).
-
-:- pred call_gen__generate_class_method_call_2(code_model, var, int, list(var),
- list(var), hlds_goal_info, code_tree, code_info, code_info).
-:- mode call_gen__generate_class_method_call_2(in, in, in, in, in, in, out, in,
- out) is det.
-
-call_gen__generate_class_method_call_2(CodeModel, TCVar, Index,
- InVars, OutVars, GoalInfo, Code) -->
- code_info__succip_is_used,
{ set__list_to_set(OutVars, OutArgs) },
call_gen__save_variables(OutArgs, SaveCode),
- (
- { CodeModel = model_det },
- { CallModel = det },
- { RuntimeAddr = do_det_class_method },
- { FlushCode = empty }
- ;
- { CodeModel = model_semi },
- { CallModel = semidet },
- { RuntimeAddr = do_semidet_class_method },
- { FlushCode = empty }
- ;
- { CodeModel = model_non },
- code_info__may_use_nondet_tailcall(TailCall),
- { CallModel = nondet(TailCall) },
- { RuntimeAddr = do_nondet_class_method },
- code_info__unset_failure_cont(FlushCode)
- ),
+ call_gen__prepare_for_call(CodeModel, FlushCode, CallModel,
+ _, DoMethodCall),
+
% place the immediate input arguments in registers
% starting at r5.
call_gen__generate_immediate_args(InVars, 5, InLocs, ImmediateCode),
@@ -332,14 +280,13 @@
),
{ call_gen__outvars_to_outargs(OutVars, FirstArg, OutArguments) },
{ call_gen__output_arg_locs(OutArguments, OutLocs) },
-
code_info__get_instmap(InstMap),
{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
{ instmap__apply_instmap_delta(InstMap, InstMapDelta,
AfterCallInstMap) },
-
call_gen__generate_return_livevals(OutArgs, OutLocs, AfterCallInstMap,
OutLiveVals),
+
code_info__produce_variable(TCVar, TCVarCode, TCVarRVal),
(
{ TCVarRVal = lval(reg(r, 1)) }
@@ -347,78 +294,75 @@
{ CopyCode = empty }
;
{ CopyCode = node([
- assign(reg(r, 1), TCVarRVal) - "Copy typeclass info"
- ])}
+ assign(reg(r, 1), TCVarRVal)
+ - "Copy typeclass info"
+ ]) }
),
{ list__length(InVars, NInVars) },
{ list__length(OutVars, NOutVars) },
- { SetupCode = tree(CopyCode, node([
- assign(reg(r, 2), const(int_const(Index))) -
- "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 = node([
+ assign(reg(r, 2), const(int_const(MethodNum))) -
+ "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"
+ ]) },
+
+ trace__prepare_for_call(TraceCode),
code_info__get_next_label(ReturnLabel),
- { TryCallCode = node([
- livevals(LiveVals) - "",
- call(RuntimeAddr, label(ReturnLabel), OutLiveVals, CallModel)
- - "setup and call class method",
- label(ReturnLabel) - "Continuation label"
+ { CallCode = node([
+ livevals(LiveVals)
+ - "",
+ call(DoMethodCall, label(ReturnLabel), OutLiveVals, CallModel)
+ - "Setup and call class method",
+ label(ReturnLabel)
+ - "Continuation label"
]) },
+
call_gen__rebuild_registers(OutArguments),
- (
- { CodeModel = model_semi }
- ->
- code_info__generate_failure(FailCode),
- code_info__get_next_label(ContLab),
- { TestSuccessCode = node([
- if_val(lval(reg(r, 1)), label(ContLab)) -
- "Test for success"
- ]) },
- { ContLabelCode = node([label(ContLab) - ""]) },
- { CallCode =
- tree(TryCallCode,
- tree(TestSuccessCode,
- tree(FailCode,
- ContLabelCode))) }
- ;
- { CallCode = TryCallCode }
- ),
+ call_gen__handle_failure(CodeModel, FailHandlingCode),
+
{ Code =
tree(SaveCode,
tree(FlushCode,
tree(ImmediateCode,
tree(TCVarCode,
+ tree(CopyCode,
tree(SetupCode,
- CallCode)))))
+ tree(TraceCode,
+ tree(CallCode,
+ FailHandlingCode))))))))
}.
%---------------------------------------------------------------------------%
:- pred call_gen__prepare_for_call(code_model, code_tree, call_model,
- code_addr, code_info, code_info).
-:- mode call_gen__prepare_for_call(in, out, out, out, in, out) is det.
+ code_addr, code_addr, code_info, code_info).
+:- mode call_gen__prepare_for_call(in, out, out, out, out, in, out) is det.
-call_gen__prepare_for_call(CodeModel, FlushCode, CallModel, RuntimeAddr) -->
+call_gen__prepare_for_call(CodeModel, FlushCode, CallModel, Higher, Method) -->
+ code_info__succip_is_used,
(
{ CodeModel = model_det },
{ CallModel = det },
- { RuntimeAddr = do_det_closure },
+ { Higher = do_det_closure },
+ { Method = do_det_class_method },
{ FlushCode = empty }
;
{ CodeModel = model_semi },
{ CallModel = semidet },
- { RuntimeAddr = do_semidet_closure },
+ { Higher = do_semidet_closure },
+ { Method = do_semidet_class_method },
{ FlushCode = empty }
;
{ CodeModel = model_non },
code_info__may_use_nondet_tailcall(TailCall),
{ CallModel = nondet(TailCall) },
- { RuntimeAddr = do_nondet_closure },
- code_info__unset_failure_cont(FlushCode)
+ { Higher = do_nondet_closure },
+ { Method = do_nondet_class_method },
+ code_info__flush_resume_vars_to_stack(FlushCode),
+ code_info__set_resume_point_and_frame_to_unknown
).
:- pred call_gen__handle_failure(code_model, code_tree, code_info, code_info).
@@ -426,13 +370,16 @@
call_gen__handle_failure(CodeModel, FailHandlingCode) -->
( { CodeModel = model_semi } ->
- code_info__generate_failure(FailCode),
code_info__get_next_label(ContLab),
{ FailTestCode = node([
if_val(lval(reg(r, 1)), label(ContLab))
- "test for success"
]) },
- { ContLabelCode = node([label(ContLab) - ""]) },
+ code_info__generate_failure(FailCode),
+ { ContLabelCode = node([
+ label(ContLab)
+ - ""
+ ]) },
{ FailHandlingCode =
tree(FailTestCode,
tree(FailCode,
@@ -508,60 +455,63 @@
%---------------------------------------------------------------------------%
-call_gen__generate_det_builtin(PredId, ProcId, Args, Code) -->
+call_gen__generate_builtin(CodeModel, PredId, ProcId, Args, Code) -->
code_info__get_module_info(ModuleInfo),
{ predicate_module(ModuleInfo, PredId, ModuleName) },
{ predicate_name(ModuleInfo, PredId, PredName) },
- (
- { code_util__translate_builtin(ModuleName, PredName, ProcId,
- Args, no, yes(Var - Rval)) }
+ {
+ code_util__translate_builtin(ModuleName, PredName,
+ ProcId, Args, MaybeTestPrime, MaybeAssignPrime)
->
- code_info__cache_expression(Var, Rval),
- { Code = empty }
+ MaybeTest = MaybeTestPrime,
+ MaybeAssign = MaybeAssignPrime
;
- { error("Unknown builtin predicate") }
- ).
-
-%---------------------------------------------------------------------------%
-
-call_gen__generate_semidet_builtin(PredId, ProcId, Args, Code) -->
- code_info__get_module_info(ModuleInfo),
- { predicate_module(ModuleInfo, PredId, ModuleName) },
- { predicate_name(ModuleInfo, PredId, PredName) },
+ error("Unknown builtin predicate")
+ },
(
- { code_util__translate_builtin(ModuleName, PredName, ProcId,
- Args, yes(Rval0), Assign) }
- ->
- ( { Rval0 = binop(BinOp, X0, Y0) } ->
- call_gen__generate_builtin_arg(X0, X, CodeX),
- call_gen__generate_builtin_arg(Y0, Y, CodeY),
- { Rval = binop(BinOp, X, Y) },
- { ArgCode = tree(CodeX, CodeY) }
- ; { Rval0 = unop(UnOp, X0) } ->
- call_gen__generate_builtin_arg(X0, X, ArgCode),
- { Rval = unop(UnOp, X) }
+ { CodeModel = model_det },
+ (
+ { MaybeTest = no },
+ { MaybeAssign = yes(Var - Rval) }
+ ->
+ code_info__cache_expression(Var, Rval),
+ { Code = empty }
;
- { error("Unknown builtin predicate") }
- ),
- code_info__fail_if_rval_is_false(Rval, TestCode),
- ( { Assign = yes(Var - AssignRval) } ->
- code_info__cache_expression(Var, AssignRval)
+ { error("Malformed det builtin predicate") }
+ )
+ ;
+ { CodeModel = model_semi },
+ (
+ { MaybeTest = yes(Test) }
+ ->
+ ( { Test = binop(BinOp, X0, Y0) } ->
+ call_gen__generate_builtin_arg(X0, X, CodeX),
+ call_gen__generate_builtin_arg(Y0, Y, CodeY),
+ { Rval = binop(BinOp, X, Y) },
+ { ArgCode = tree(CodeX, CodeY) }
+ ; { Test = unop(UnOp, X0) } ->
+ call_gen__generate_builtin_arg(X0, X, ArgCode),
+ { Rval = unop(UnOp, X) }
+ ;
+ { error("Malformed semi builtin predicate") }
+ ),
+ code_info__fail_if_rval_is_false(Rval, TestCode),
+ ( { MaybeAssign = yes(Var - AssignRval) } ->
+ code_info__cache_expression(Var, AssignRval)
+ ;
+ []
+ ),
+ { Code = tree(ArgCode, TestCode) }
;
- []
- ),
- { Code = tree(ArgCode, TestCode) }
+ { error("Malformed semi builtin predicate") }
+ )
;
- { error("Unknown builtin predicate") }
+ { CodeModel = model_non },
+ { error("Nondet builtin predicate") }
).
%---------------------------------------------------------------------------%
-call_gen__generate_nondet_builtin(_PredId, _ProcId, _Args, _Code) -->
- % there aren't any nondet builtins
- { error("Unknown nondet builtin predicate") }.
-
-%---------------------------------------------------------------------------%
-
:- 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.
@@ -588,88 +538,6 @@
call_gen__partition_args(Rest, Ins, Outs0),
Outs = [V | Outs0]
).
-
-%---------------------------------------------------------------------------%
-
-/* DEAD CODE
-call_gen__generate_complicated_unify(Var1, Var2, UniMode, CanFail, Code) -->
- { determinism_components(Det, CanFail, at_most_one) },
- { determinism_to_code_model(Det, CodeModel) },
- code_info__get_globals(Globals),
- { globals__get_args_method(Globals, ArgsMethod) },
- { arg_info__unify_arg_info(ArgsMethod, CodeModel, ArgInfo) },
- { Arguments = [Var1, Var2] },
- { assoc_list__from_corresponding_lists(Arguments, ArgInfo, Args) },
- { call_gen__select_out_args(Args, OutArgs) },
- call_gen__save_variables(OutArgs, CodeA),
- code_info__setup_call(Args, caller, CodeB),
- code_info__get_next_label(ReturnLabel),
- code_info__get_module_info(ModuleInfo),
- code_info__variable_type(Var1, VarType),
- ( { type_to_type_id(VarType, VarTypeId, _) } ->
- { unify_proc__lookup_mode_num(ModuleInfo, VarTypeId, UniMode,
- Det, ModeNum) },
- { call_gen__input_args(ArgInfo, InputArguments) },
- call_gen__generate_call_livevals(OutArgs, InputArguments,
- CodeC0),
- { call_gen__output_arg_locs(Args, OutputArguments) },
- call_gen__generate_return_livevals(OutArgs, OutputArguments,
- GoalInfo, OutLiveVals),
- { code_util__make_uni_label(ModuleInfo, VarTypeId, ModeNum,
- UniLabel) },
- { Address = imported(UniLabel) },
- /\************
- % Currently we just conservatively assume the address
- % of a unification predicate is imported. For
- % non-standard modes, we could do better, if
- % procs_per_c_function is zero (meaning infinity),
- % or if it is a recursive call.
- % But the code below doesn't work if procs_per_c_function
- % is non-zero and it's not a recursive call.
- { ModeNum = 0 ->
- Address = imported(UniLabel)
- ;
- Address = label(local(UniLabel))
- },
- **************\/
- (
- { CanFail = can_fail }
- ->
- { CallModel = semidet }
- ;
- { CallModel = det }
- ),
- { CodeC1 = node([
- call(Address, label(ReturnLabel),
- OutLiveVals, CallModel)
- - "branch to out-of-line unification procedure",
- label(ReturnLabel) - "Continuation label"
- ]) }
- ;
- % `type_to_type_id' failed - the type must be a type variable,
- % i.e. it is a polymorphic unification.
- % However, these sorts of unifications should have been changed
- % into calls to unify/2 by polymorphism.m, so if we encounter
- % any here, it's an internal error.
- { error("unexpected polymorphic unification") }
- ),
- (
- { CanFail = can_fail }
- ->
- code_info__get_next_label(ContLab),
- call_gen__rebuild_registers(Args),
- code_info__generate_failure(FailCode),
- { CodeD = tree(node([
- if_val(lval(reg(r(1))), label(ContLab)) -
- "Test for success"
- ]), tree(FailCode, node([ label(ContLab) - "" ]))) }
- ;
- call_gen__rebuild_registers(Args),
- { CodeD = empty }
- ),
-
- { Code = tree(CodeA, tree(CodeB, tree(tree(CodeC0, CodeC1), CodeD))) }.
-*/
%---------------------------------------------------------------------------%
Index: compiler/code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_gen.m,v
retrieving revision 1.52
diff -u -r1.52 code_gen.m
--- code_gen.m 1998/06/18 06:05:48 1.52
+++ code_gen.m 1998/07/02 04:19:14
@@ -1,28 +1,29 @@
%---------------------------------------------------------------------------%
-% Copyright (C) 1996-1998 The University of Melbourne.
+% Copyright (C) 1994-1998 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.
%---------------------------------------------------------------------------%
%
% Code generation - convert from HLDS to LLDS.
%
-% Main author: conway.
+% Main authors: conway, zs.
%
-% Notes:
+% The two main tasks of this module are
%
-% code_gen forwards most of the actual construction of intruction
-% sequences to code_info, and other modules. The generation of
-% calls is done by call_gen, switches by switch_gen, if-then-elses
-% by ite_gen, unifications by unify_gen, disjunctions by disj_gen,
-% and pragma_c_codes by pragma_c_gen.
+% 1 to look after the aspects of generating code for a procedure
+% that do not involve generating code for a specific goal, and
%
-% The general scheme for generating semideterministic code is
-% to treat it as deterministic code, and have a fall-through
-% point for failure. Semideterministic procedures leave a 'true'
-% in register r(1) to indicate success, and 'false' to indicate
-% failure.
+% 2 to provide a generic predicate that can be called from anywhere in
+% the code generator to generate code for a goal.
+%
+% Code_gen forwards most of the actual construction of code for particular
+% goals to other modules. The generation of code for unifications is done
+% by unify_gen, for calls, higher-order calls and method calls by call_gen,
+% for commits by commit_gen, for if-then-elses and negations by ite_gen,
+% for switches by switch_gen and its subsidiary modules, for disjunctions
+% by disj_gen, and for pragma_c_codes by pragma_c_gen. The only kind of goal
+% handled directly by code_gen is the conjunction.
%
-%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- module code_gen.
@@ -31,26 +32,27 @@
:- import_module hlds_module, hlds_pred, hlds_goal, llds, code_info.
:- import_module continuation_info, globals.
-:- import_module set, list, assoc_list, term, io.
+:- import_module list, io.
- % Translate a HLDS structure into an LLDS
+ % Translate a HLDS module to LLDS.
-:- pred generate_code(module_info, module_info, list(c_procedure),
- io__state, io__state).
-:- mode generate_code(in, out, out, di, uo) is det.
+:- pred generate_code(module_info::in, module_info::out,
+ list(c_procedure)::out, io__state::di, io__state::uo) is det.
-:- pred generate_proc_code(proc_info, proc_id, pred_id, module_info, globals,
- continuation_info, int, continuation_info, int, c_procedure).
-:- mode generate_proc_code(in, in, in, in, in, in, in, out, out, out) is det.
+ % Translate a HLDS procedure to LLDS, threading through
+ % the data structure that records information about layout
+ % structures and the counter for ensuring the uniqueness
+ % of cell numbers.
- % This predicate generates code for a goal.
+:- pred generate_proc_code(proc_info::in, proc_id::in, pred_id::in,
+ module_info::in, globals::in,
+ continuation_info::in, continuation_info::out, int::in, int::out,
+ c_procedure::out) is det.
-:- pred code_gen__generate_goal(code_model, hlds_goal, code_tree,
- code_info, code_info).
-:- mode code_gen__generate_goal(in, in, out, in, out) is det.
+ % Translate a HLDS goal to LLDS.
-:- pred code_gen__output_args(assoc_list(var, arg_info), set(lval)).
-:- mode code_gen__output_args(in, out) is det.
+:- pred code_gen__generate_goal(code_model::in, hlds_goal::in, code_tree::out,
+ code_info::in, code_info::out) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
@@ -58,18 +60,16 @@
:- implementation.
:- import_module call_gen, unify_gen, ite_gen, switch_gen, disj_gen.
-:- import_module par_conj_gen, pragma_c_gen, trace, options, hlds_out.
+:- import_module par_conj_gen, pragma_c_gen, commit_gen.
+:- import_module trace, options, hlds_out.
:- import_module code_aux, middle_rec, passes_aux, llds_out.
:- import_module code_util, type_util, mode_util.
:- import_module prog_data, prog_out, instmap.
:- import_module bool, char, int, string.
-:- import_module map, tree, std_util, require, varset.
+:- import_module map, assoc_list, set, term, tree, std_util, require, varset.
%---------------------------------------------------------------------------%
-% For a set of high level data structures and associated data, given in
-% ModuleInfo, generate a list of c_procedure structures.
-
generate_code(ModuleInfo0, ModuleInfo, Procedures) -->
% get a list of all the predicate ids
% for which we are going to generate code.
@@ -77,12 +77,11 @@
% now generate the code for each predicate
generate_pred_list_code(ModuleInfo0, ModuleInfo, PredIds, Procedures).
-% Generate a list of c_procedure structures for each mode of each
-% predicate given in ModuleInfo
+ % Translate a list of HLDS predicates to LLDS.
-:- pred generate_pred_list_code(module_info, module_info, list(pred_id),
- list(c_procedure), io__state, io__state).
-:- mode generate_pred_list_code(in, out, in, out, di, uo) is det.
+:- pred generate_pred_list_code(module_info::in, module_info::out,
+ list(pred_id)::in, list(c_procedure)::out,
+ io__state::di, io__state::uo) is det.
generate_pred_list_code(ModuleInfo, ModuleInfo, [], []) --> [].
generate_pred_list_code(ModuleInfo0, ModuleInfo, [PredId | PredIds],
@@ -104,12 +103,11 @@
% and generate the code for the rest of the predicates
generate_pred_list_code(ModuleInfo1, ModuleInfo, PredIds, Predicates1).
-% For the predicate identified by PredId, with the the associated
-% data in ModuleInfo, generate a code_tree.
+ % Translate a HLDS predicate to LLDS.
-:- pred generate_pred_code(module_info, module_info, pred_id, pred_info,
- list(proc_id), list(c_procedure), io__state, io__state).
-:- mode generate_pred_code(in, out, in, in, in, out, di, uo) is det.
+:- pred generate_pred_code(module_info::in, module_info::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, PredId, PredInfo, ProcIds, Code) -->
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
@@ -122,7 +120,6 @@
;
[]
),
- % generate all the procedures for this predicate
{ module_info_get_continuation_info(ModuleInfo0, ContInfo0) },
{ module_info_get_cell_count(ModuleInfo0, CellCount0) },
globals__io_get_globals(Globals),
@@ -133,16 +130,12 @@
{ module_info_set_continuation_info(ModuleInfo1, ContInfo,
ModuleInfo) }.
-% For all the modes of predicate PredId, generate the appropriate
-% code (deterministic, semideterministic, or nondeterministic).
+ % Translate all the procedures of a HLDS predicate to LLDS.
-:- pred generate_proc_list_code(list(proc_id), pred_id, pred_info, module_info,
- globals, continuation_info, continuation_info, int, int,
- list(c_procedure), list(c_procedure)).
-% :- mode generate_proc_list_code(in, in, in, in, in, di, uo, di, uo)
-% is det.
-:- mode generate_proc_list_code(in, in, in, in, in, in, out, in, out, in, out)
- is det.
+:- pred generate_proc_list_code(list(proc_id)::in, pred_id::in, pred_info::in,
+ module_info::in, globals::in,
+ continuation_info::in, continuation_info::out, int::in, int::out,
+ list(c_procedure)::in, list(c_procedure)::out) is det.
generate_proc_list_code([], _PredId, _PredInfo, _ModuleInfo, _Globals,
ContInfo, ContInfo, CellCount, CellCount, Procs, Procs).
@@ -150,10 +143,9 @@
Globals, ContInfo0, ContInfo, CellCount0, CellCount,
Procs0, Procs) :-
pred_info_procedures(PredInfo, ProcInfos),
- % locate the proc_info structure for this mode of the predicate
map__lookup(ProcInfos, ProcId, ProcInfo),
generate_proc_code(ProcInfo, ProcId, PredId, ModuleInfo0, Globals,
- ContInfo0, CellCount0, ContInfo1, CellCount1, Proc),
+ ContInfo0, ContInfo1, CellCount0, CellCount1, Proc),
generate_proc_list_code(ProcIds, PredId, PredInfo, ModuleInfo0,
Globals, ContInfo1, ContInfo, CellCount1, CellCount,
[Proc | Procs0], Procs).
@@ -179,13 +171,10 @@
%---------------------------------------------------------------------------%
generate_proc_code(ProcInfo, ProcId, PredId, ModuleInfo, Globals,
- ContInfo0, CellCount0, ContInfo, CellCount, Proc) :-
- % find out if the proc is deterministic/etc
+ ContInfo0, ContInfo, CellCount0, CellCount, Proc) :-
proc_info_interface_determinism(ProcInfo, Detism),
proc_info_interface_code_model(ProcInfo, CodeModel),
- % get the goal for this procedure
proc_info_goal(ProcInfo, Goal),
- % get the information about this procedure that we need.
proc_info_varset(ProcInfo, VarSet),
proc_info_liveness_info(ProcInfo, Liveness),
proc_info_stack_slots(ProcInfo, StackSlots),
@@ -205,39 +194,45 @@
;
SaveSuccip = no
),
- % initialise the code_info structure
+ % Initialise the code_info structure. Generate_category_code
+ % below will use the returned OutsideResumePoint as the
+ % entry to the code that handles the failure of the procedure,
+ % if such code is needed. It is never needed for model_det
+ % procedures, always needed for model_semi procedures, and
+ % needed for model_non procedures only if we are doing
+ % execution tracing.
code_info__init(VarSet, Liveness, StackSlots, SaveSuccip, Globals,
PredId, ProcId, ProcInfo, InitialInst, FollowVars,
- ModuleInfo, CellCount0, CodeInfo0),
- % generate code for the procedure
- globals__get_trace_level(Globals, TraceLevel),
- code_util__make_proc_label(ModuleInfo, PredId, ProcId, ProcLabel),
- ( trace_level_trace_interface(TraceLevel, yes) ->
- trace__setup(TraceLevel, CodeInfo0, CodeInfo1)
- ;
- CodeInfo1 = CodeInfo0
- ),
- generate_category_code(CodeModel, Goal, ProcInfo, CodeTree,
- MaybeTraceCallLabel, FrameInfo, CodeInfo1, CodeInfo),
- % extract the new continuation_info and cell count
- code_info__get_cell_count(CellCount, CodeInfo, _CodeInfo1),
+ ModuleInfo, CellCount0, OutsideResumePoint, CodeInfo0),
+
+ % Generate code for the procedure.
+ generate_category_code(CodeModel, Goal, OutsideResumePoint,
+ CodeTree, MaybeTraceCallLabel, FrameInfo, CodeInfo0, CodeInfo),
+ code_info__get_cell_count(CellCount, CodeInfo, _),
- % turn the code tree into a list
+ % Turn the code tree into a list.
tree__flatten(CodeTree, FragmentList),
- % now the code is a list of code fragments (== list(instr)),
+ % Now the code is a list of code fragments (== list(instr)),
% so we need to do a level of unwinding to get a flat list.
list__condense(FragmentList, Instructions0),
FrameInfo = frame(TotalSlots, MaybeSuccipSlot, _),
(
MaybeSuccipSlot = yes(SuccipSlot)
->
+ % The set of recorded live values at calls (for value
+ % numbering) and returns (for accurate gc and execution
+ % tracing) do not yet record the stack slot holding the
+ % succip, so add it to those sets.
code_gen__add_saved_succip(Instructions0,
SuccipSlot, Instructions)
;
Instructions = Instructions0
),
( BasicStackLayout = yes ->
- code_info__get_layout_info(LayoutInfo, CodeInfo, _CodeInfo2),
+ % Create the procedure layout structure.
+ code_util__make_proc_label(ModuleInfo, PredId, ProcId,
+ ProcLabel),
+ code_info__get_layout_info(LayoutInfo, CodeInfo, _),
continuation_info__add_proc_info(proc(PredId, ProcId),
ProcLabel, TotalSlots, Detism, MaybeSuccipSlot,
MaybeTraceCallLabel, LayoutInfo, ContInfo0, ContInfo)
@@ -245,13 +240,13 @@
ContInfo = ContInfo0
),
- % get the name and arity of this predicate
predicate_name(ModuleInfo, PredId, Name),
predicate_arity(ModuleInfo, PredId, Arity),
- % construct a c_procedure structure with all the information
+ % Construct a c_procedure structure with all the information.
Proc = c_procedure(Name, Arity, proc(PredId, ProcId), Instructions).
%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
% Generate_category_code generates code for an entire procedure.
% Its algorithm has three or four main stages:
@@ -296,11 +291,11 @@
% continuation needs no code. Only model_semi procedures need code
% for the failure continuation at all times.)
-:- pred generate_category_code(code_model, hlds_goal, proc_info, code_tree,
- maybe(label), frame_info, code_info, code_info).
-:- mode generate_category_code(in, in, in, out, out, out, in, out) is det.
+:- pred generate_category_code(code_model::in, hlds_goal::in,
+ resume_point_info::in, code_tree::out, maybe(label)::out,
+ frame_info::out, code_info::in, code_info::out) is det.
-generate_category_code(model_det, Goal, ProcInfo, Code,
+generate_category_code(model_det, Goal, ResumePoint, Code,
MaybeTraceCallLabel, FrameInfo) -->
% generate the code for the body of the clause
(
@@ -312,18 +307,8 @@
{ MaybeTraceCallLabel = no },
{ FrameInfo = frame(0, no, no) }
;
- % make a new failure cont (not model_non);
- % this continuation is never actually used,
- % but is a place holder
- code_info__manufacture_failure_cont(no),
-
code_info__get_maybe_trace_info(MaybeTraceInfo),
( { MaybeTraceInfo = yes(TraceInfo) } ->
- code_info__get_module_info(ModuleInfo),
- { trace__fail_vars(ModuleInfo, ProcInfo, ResumeVars) },
- % Protect these vars from being forgotten,
- % so they will be around for the exit trace.
- code_info__push_resume_point_vars(ResumeVars),
trace__generate_external_event_code(call, TraceInfo,
TraceCallLabel, _TypeInfos, TraceCallCode),
{ MaybeTraceCallLabel = yes(TraceCallLabel) }
@@ -332,8 +317,8 @@
{ MaybeTraceCallLabel = no }
),
code_gen__generate_goal(model_det, Goal, BodyCode),
- code_gen__generate_entry(model_det, Goal, FrameInfo,
- EntryCode),
+ code_gen__generate_entry(model_det, Goal, ResumePoint,
+ FrameInfo, EntryCode),
code_gen__generate_exit(model_det, FrameInfo, _, ExitCode),
{ Code =
tree(EntryCode,
@@ -343,55 +328,49 @@
}
).
-generate_category_code(model_semi, Goal, ProcInfo, Code,
+generate_category_code(model_semi, Goal, ResumePoint, Code,
MaybeTraceCallLabel, FrameInfo) -->
- % make a new failure cont (not model_non)
- code_info__manufacture_failure_cont(no),
- code_info__get_maybe_trace_info(MaybeTraceInfo),
{ set__singleton_set(FailureLiveRegs, reg(r, 1)) },
{ FailCode = node([
assign(reg(r, 1), const(false)) - "Fail",
livevals(FailureLiveRegs) - "",
goto(succip) - "Return from procedure call"
]) },
+ code_info__get_maybe_trace_info(MaybeTraceInfo),
( { MaybeTraceInfo = yes(TraceInfo) } ->
- code_info__get_module_info(ModuleInfo),
- { trace__fail_vars(ModuleInfo, ProcInfo, ResumeVars) },
- code_info__make_known_failure_cont(ResumeVars, orig_and_stack,
- no, SetupCode),
- code_info__push_resume_point_vars(ResumeVars),
trace__generate_external_event_code(call, TraceInfo,
TraceCallLabel, _TypeInfos, TraceCallCode),
{ MaybeTraceCallLabel = yes(TraceCallLabel) },
code_gen__generate_goal(model_semi, Goal, BodyCode),
- code_gen__generate_entry(model_semi, Goal, FrameInfo,
- EntryCode),
+ code_gen__generate_entry(model_semi, Goal, ResumePoint,
+ FrameInfo, EntryCode),
code_gen__generate_exit(model_semi, FrameInfo,
RestoreDeallocCode, ExitCode),
- code_info__pop_resume_point_vars,
- code_info__restore_failure_cont(ResumeCode),
+
+ code_info__generate_resume_point(ResumePoint, ResumeCode),
+ { code_info__resume_point_vars(ResumePoint, ResumeVarList) },
+ { set__list_to_set(ResumeVarList, ResumeVars) },
code_info__set_forward_live_vars(ResumeVars),
trace__generate_external_event_code(fail, TraceInfo, _, _,
TraceFailCode),
{ Code =
tree(EntryCode,
- tree(SetupCode,
tree(TraceCallCode,
tree(BodyCode,
tree(ExitCode,
tree(ResumeCode,
tree(TraceFailCode,
tree(RestoreDeallocCode,
- FailCode))))))))
+ FailCode)))))))
}
;
{ MaybeTraceCallLabel = no },
code_gen__generate_goal(model_semi, Goal, BodyCode),
- code_gen__generate_entry(model_semi, Goal, FrameInfo,
- EntryCode),
+ code_gen__generate_entry(model_semi, Goal, ResumePoint,
+ FrameInfo, EntryCode),
code_gen__generate_exit(model_semi, FrameInfo,
RestoreDeallocCode, ExitCode),
- code_info__restore_failure_cont(ResumeCode),
+ code_info__generate_resume_point(ResumePoint, ResumeCode),
{ Code =
tree(EntryCode,
tree(BodyCode,
@@ -402,52 +381,46 @@
}
).
-generate_category_code(model_non, Goal, ProcInfo, Code,
+generate_category_code(model_non, Goal, ResumePoint, Code,
MaybeTraceCallLabel, FrameInfo) -->
- % make a new failure cont (yes, it is model_non)
- code_info__manufacture_failure_cont(yes),
- % we must arrange the tracing of failure out of this proc
code_info__get_maybe_trace_info(MaybeTraceInfo),
( { MaybeTraceInfo = yes(TraceInfo) } ->
- code_info__get_module_info(ModuleInfo),
- { trace__fail_vars(ModuleInfo, ProcInfo, ResumeVars) },
- code_info__make_known_failure_cont(ResumeVars, orig_and_stack,
- yes, SetupCode),
- code_info__push_resume_point_vars(ResumeVars),
trace__generate_external_event_code(call, TraceInfo,
TraceCallLabel, _TypeInfos, TraceCallCode),
{ MaybeTraceCallLabel = yes(TraceCallLabel) },
code_gen__generate_goal(model_non, Goal, BodyCode),
- code_gen__generate_entry(model_non, Goal, FrameInfo,
- PrologCode),
- code_gen__generate_exit(model_non, FrameInfo, _, EpilogCode),
-
- code_info__pop_resume_point_vars,
- code_info__restore_failure_cont(RestoreCode),
+ code_gen__generate_entry(model_non, Goal, ResumePoint,
+ FrameInfo, EntryCode),
+ code_gen__generate_exit(model_non, FrameInfo, _, ExitCode),
+
+ code_info__generate_resume_point(ResumePoint, ResumeCode),
+ { code_info__resume_point_vars(ResumePoint, ResumeVarList) },
+ { set__list_to_set(ResumeVarList, ResumeVars) },
code_info__set_forward_live_vars(ResumeVars),
trace__generate_external_event_code(fail, TraceInfo, _, _,
TraceFailCode),
- code_info__generate_failure(FailCode),
+ { FailCode = node([
+ goto(do_fail) - "fail after fail trace port"
+ ]) },
{ Code =
- tree(PrologCode,
- tree(SetupCode,
+ tree(EntryCode,
tree(TraceCallCode,
tree(BodyCode,
- tree(EpilogCode,
- tree(RestoreCode,
+ tree(ExitCode,
+ tree(ResumeCode,
tree(TraceFailCode,
- FailCode)))))))
+ FailCode))))))
}
;
{ MaybeTraceCallLabel = no },
code_gen__generate_goal(model_non, Goal, BodyCode),
- code_gen__generate_entry(model_non, Goal, FrameInfo,
- PrologCode),
- code_gen__generate_exit(model_non, FrameInfo, _, EpilogCode),
+ code_gen__generate_entry(model_non, Goal, ResumePoint,
+ FrameInfo, EntryCode),
+ code_gen__generate_exit(model_non, FrameInfo, _, ExitCode),
{ Code =
- tree(PrologCode,
+ tree(EntryCode,
tree(BodyCode,
- EpilogCode))
+ ExitCode))
}
).
@@ -472,11 +445,12 @@
% need a stack frame, and if the procedure is nondet, then the code
% to fill in the succip slot is subsumed by the mkframe.
-:- pred code_gen__generate_entry(code_model, hlds_goal, frame_info,
- code_tree, code_info, code_info).
-:- mode code_gen__generate_entry(in, in, out, out, in, out) is det.
+:- pred code_gen__generate_entry(code_model::in, hlds_goal::in,
+ resume_point_info::in, frame_info::out, code_tree::out,
+ code_info::in, code_info::out) is det.
-code_gen__generate_entry(CodeModel, Goal, FrameInfo, PrologCode) -->
+code_gen__generate_entry(CodeModel, Goal, OutsideResumePoint,
+ FrameInfo, EntryCode) -->
code_info__get_stack_slots(StackSlots),
code_info__get_varset(VarSet),
{ code_aux__explain_stack_slots(StackSlots, VarSet, SlotsComment) },
@@ -529,6 +503,8 @@
(
{ CodeModel = model_non }
->
+ { code_info__resume_point_stack_addr(OutsideResumePoint,
+ OutsideResumeAddress) },
(
{ Goal = pragma_c_code(_,_,_,_,_,_, PragmaCode) - _},
{ PragmaCode = nondet(Fields, FieldsContext,
@@ -541,9 +517,10 @@
{ string__format("#define\tMR_ORDINARY_SLOTS\t%d\n",
[i(TotalSlots)], DefineStr) },
{ DefineComponents = [pragma_c_raw_code(DefineStr)] },
+ { NondetFrameInfo = ordinary_frame(PushMsg, TotalSlots,
+ yes(Struct)) },
{ AllocCode = node([
- mkframe(PushMsg, TotalSlots, yes(Struct),
- do_fail)
+ mkframe(NondetFrameInfo, OutsideResumeAddress)
- "Allocate stack frame",
pragma_c([], DefineComponents,
will_not_call_mercury, no, no)
@@ -551,9 +528,11 @@
]) },
{ NondetPragma = yes }
;
+ { NondetFrameInfo = ordinary_frame(PushMsg, TotalSlots,
+ no) },
{ AllocCode = node([
- mkframe(PushMsg, TotalSlots, no, do_fail) -
- "Allocate stack frame"
+ mkframe(NondetFrameInfo, OutsideResumeAddress)
+ - "Allocate stack frame"
]) },
{ NondetPragma = no }
)
@@ -573,7 +552,7 @@
{ EndComment = node([
comment("End of procedure prologue") - ""
]) },
- { PrologCode =
+ { EntryCode =
tree(StartComment,
tree(LabelCode,
tree(AllocCode,
@@ -612,12 +591,10 @@
% of the epilogue are handled when traversing the pragma C code goal;
% we need only #undef a macro defined by the procedure prologue.
-:- pred code_gen__generate_exit(code_model, frame_info, code_tree, code_tree,
- code_info, code_info).
-:- mode code_gen__generate_exit(in, in, out, out, in, out) is det.
+:- pred code_gen__generate_exit(code_model::in, frame_info::in,
+ code_tree::out, code_tree::out, code_info::in, code_info::out) is det.
-code_gen__generate_exit(CodeModel, FrameInfo, RestoreDeallocCode, EpilogCode)
- -->
+code_gen__generate_exit(CodeModel, FrameInfo, RestoreDeallocCode, ExitCode) -->
{ StartComment = node([
comment("Start of procedure epilogue") - ""
]) },
@@ -634,7 +611,7 @@
- ""
]) },
{ RestoreDeallocCode = empty }, % always empty for nondet code
- { EpilogCode =
+ { ExitCode =
tree(StartComment,
tree(UndefCode,
EndComment))
@@ -727,7 +704,7 @@
SuccessCode)
}
),
- { EpilogCode =
+ { ExitCode =
tree(StartComment,
tree(FlushCode,
tree(AllSuccessCode,
@@ -754,26 +731,29 @@
{ instmap__is_reachable(Instmap) }
->
{ goal_info_get_code_model(GoalInfo, CodeModel) },
- (
- { CodeModel = model_det },
- code_gen__generate_det_goal_2(Goal, GoalInfo, Code)
- ;
- { CodeModel = model_semi },
- ( { ContextModel \= model_det } ->
- code_gen__generate_semi_goal_2(Goal, GoalInfo,
- Code)
+
+ % sanity check: code of some code models
+ % should occur only in limited contexts
+ {
+ CodeModel = model_det
+ ;
+ CodeModel = model_semi,
+ ( ContextModel \= model_det ->
+ true
;
- { error("semidet model in det context") }
+ error("semidet model in det context")
)
;
- { CodeModel = model_non },
- ( { ContextModel = model_non } ->
- code_gen__generate_non_goal_2(Goal, GoalInfo,
- Code)
+ CodeModel = model_non,
+ ( ContextModel = model_non ->
+ true
;
- { error("nondet model in det/semidet context") }
+ error("nondet model in det/semidet context")
)
- ),
+ },
+
+ code_gen__generate_goal_2(Goal, GoalInfo, CodeModel, Code),
+
% Make live any variables which subsequent goals
% will expect to be live, but were not generated
code_info__set_instmap(Instmap),
@@ -785,399 +765,80 @@
%---------------------------------------------------------------------------%
-% Generate a conjoined series of goals.
-% Note of course, that with a conjunction, state information
-% flows directly from one conjunct to the next.
-
-:- pred code_gen__generate_goals(hlds_goals, code_model, code_tree,
- code_info, code_info).
-:- mode code_gen__generate_goals(in, in, out, in, out) is det.
+:- pred code_gen__generate_goal_2(hlds_goal_expr::in, hlds_goal_info::in,
+ code_model::in, code_tree::out, code_info::in, code_info::out) is det.
-code_gen__generate_goals([], _, empty) --> [].
-code_gen__generate_goals([Goal | Goals], CodeModel, Instr) -->
- code_gen__generate_goal(CodeModel, Goal, Instr1),
- code_info__get_instmap(Instmap),
- (
- { instmap__is_unreachable(Instmap) }
- ->
- { Instr = Instr1 }
- ;
- code_gen__generate_goals(Goals, CodeModel, Instr2),
- { Instr = tree(Instr1, Instr2) }
- ).
-
-%---------------------------------------------------------------------------%
-
-:- pred code_gen__generate_det_goal_2(hlds_goal_expr, hlds_goal_info,
- code_tree, code_info, code_info).
-:- mode code_gen__generate_det_goal_2(in, in, out, in, out) is det.
-
-code_gen__generate_det_goal_2(conj(Goals), _GoalInfo, Instr) -->
- code_gen__generate_goals(Goals, model_det, Instr).
-code_gen__generate_det_goal_2(par_conj(Goals, _StoreMap), GoalInfo, Instr) -->
- par_conj_gen__generate_det_par_conj(Goals, GoalInfo, Instr).
-code_gen__generate_det_goal_2(some(_Vars, Goal), _GoalInfo, Instr) -->
- { Goal = _ - InnerGoalInfo },
- { goal_info_get_code_model(InnerGoalInfo, CodeModel) },
- (
- { CodeModel = model_det },
- code_gen__generate_goal(model_det, Goal, Instr)
- ;
- { CodeModel = model_semi },
- { error("semidet model in det context") }
- ;
- { CodeModel = model_non },
- code_info__generate_det_pre_commit(Slots, PreCommit),
- code_gen__generate_goal(model_non, Goal, GoalCode),
- code_info__generate_det_commit(Slots, Commit),
- { Instr = tree(PreCommit, tree(GoalCode, Commit)) }
- ).
-code_gen__generate_det_goal_2(disj(Goals, StoreMap), _GoalInfo, Instr) -->
- disj_gen__generate_det_disj(Goals, StoreMap, Instr).
-code_gen__generate_det_goal_2(not(Goal), _GoalInfo, Instr) -->
- code_gen__generate_negation(model_det, Goal, Instr).
-code_gen__generate_det_goal_2(higher_order_call(PredVar, Args, Types,
- Modes, Det, _PredOrFunc),
- GoalInfo, Instr) -->
- call_gen__generate_higher_order_call(model_det, PredVar, Args,
- Types, Modes, Det, GoalInfo, Instr).
-code_gen__generate_det_goal_2(class_method_call(TCVar, Num, Args, Types,
- Modes, Det),
- GoalInfo, Instr) -->
- call_gen__generate_class_method_call(model_det, TCVar, Num, Args,
- Types, Modes, Det, GoalInfo, Instr).
-code_gen__generate_det_goal_2(call(PredId, ProcId, Args, BuiltinState, _, _),
- GoalInfo, Instr) -->
- (
- { BuiltinState = not_builtin }
- ->
- code_info__succip_is_used,
- call_gen__generate_call(model_det, PredId, ProcId, Args,
- GoalInfo, Instr)
- ;
- call_gen__generate_det_builtin(PredId, ProcId, Args, Instr)
- ).
-code_gen__generate_det_goal_2(switch(Var, CanFail, CaseList, StoreMap),
- GoalInfo, Instr) -->
- switch_gen__generate_switch(model_det, Var, CanFail, CaseList,
- StoreMap, GoalInfo, Instr).
-code_gen__generate_det_goal_2(
- if_then_else(_Vars, CondGoal, ThenGoal, ElseGoal, StoreMap),
- _GoalInfo, Instr) -->
- ite_gen__generate_det_ite(CondGoal, ThenGoal, ElseGoal, StoreMap,
- Instr).
-code_gen__generate_det_goal_2(unify(_L, _R, _U, Uni, _C), _GoalInfo, Instr) -->
- (
- { Uni = assign(Left, Right) },
- unify_gen__generate_assignment(Left, Right, Instr)
- ;
- { Uni = construct(Var, ConsId, Args, Modes) },
- unify_gen__generate_construction(Var, ConsId, Args,
- Modes, Instr)
- ;
- { Uni = deconstruct(Var, ConsId, Args, Modes, _Det) },
- unify_gen__generate_det_deconstruction(Var, ConsId, Args,
- Modes, Instr)
- ;
- % These should have been transformed into calls by
- % polymorphism.m.
- { Uni = complicated_unify(_UniMode, _CanFail) },
- { error("code_gen__generate_det_goal_2 - complicated unify") }
- ;
- { Uni = simple_test(_, _) },
- { error("generate_det_goal_2: cannot have det simple_test") }
- ).
-
-code_gen__generate_det_goal_2(pragma_c_code(MayCallMercury,
- PredId, ModeId, Args, ArgNames, OrigArgTypes, PragmaCode),
- GoalInfo, Instr) -->
- pragma_c_gen__generate_pragma_c_code(model_det, MayCallMercury,
- PredId, ModeId, Args, ArgNames, OrigArgTypes, GoalInfo,
- PragmaCode, Instr).
-
-%---------------------------------------------------------------------------%
-
-:- pred code_gen__generate_semi_goal_2(hlds_goal_expr, hlds_goal_info,
- code_tree, code_info, code_info).
-:- mode code_gen__generate_semi_goal_2(in, in, out, in, out) is det.
-
-code_gen__generate_semi_goal_2(conj(Goals), _GoalInfo, Code) -->
- code_gen__generate_goals(Goals, model_semi, Code).
-code_gen__generate_semi_goal_2(par_conj(_Goals, _SM), _GoalInfo, _Code) -->
- % Determinism analysis will report a determinism error if the
- % parallel conj is not det.
- { error("sorry, semidet parallel conjunction not implemented") }.
-code_gen__generate_semi_goal_2(some(_Vars, Goal), _GoalInfo, Code) -->
- { Goal = _ - InnerGoalInfo },
- { goal_info_get_code_model(InnerGoalInfo, CodeModel) },
- (
- { CodeModel = model_det },
- code_gen__generate_goal(model_det, Goal, Code)
- ;
- { CodeModel = model_semi },
- code_gen__generate_goal(model_semi, Goal, Code)
- ;
- { CodeModel = model_non },
- code_info__generate_semi_pre_commit(Label, Slots, PreCommit),
- code_gen__generate_goal(model_non, Goal, GoalCode),
- code_info__generate_semi_commit(Label, Slots, Commit),
- { Code = tree(PreCommit, tree(GoalCode, Commit)) }
- ).
-code_gen__generate_semi_goal_2(disj(Goals, StoreMap), _GoalInfo, Code) -->
- disj_gen__generate_semi_disj(Goals, StoreMap, Code).
-code_gen__generate_semi_goal_2(not(Goal), _GoalInfo, Code) -->
- code_gen__generate_negation(model_semi, Goal, Code).
-code_gen__generate_semi_goal_2(higher_order_call(PredVar, Args, Types, Modes,
- Det, _PredOrFunc), GoalInfo, Code) -->
- call_gen__generate_higher_order_call(model_semi, PredVar, Args,
+code_gen__generate_goal_2(unify(_, _, _, Uni, _), _, CodeModel, Code) -->
+ unify_gen__generate_unification(CodeModel, Uni, Code).
+code_gen__generate_goal_2(conj(Goals), _GoalInfo, CodeModel, Code) -->
+ code_gen__generate_goals(Goals, CodeModel, Code).
+code_gen__generate_goal_2(par_conj(Goals, _SM), GoalInfo, CodeModel, Code) -->
+ par_conj_gen__generate_par_conj(Goals, GoalInfo, CodeModel, Code).
+code_gen__generate_goal_2(disj(Goals, StoreMap), _, CodeModel, Code) -->
+ disj_gen__generate_disj(CodeModel, Goals, StoreMap, Code).
+code_gen__generate_goal_2(not(Goal), _GoalInfo, CodeModel, Code) -->
+ ite_gen__generate_negation(CodeModel, Goal, Code).
+code_gen__generate_goal_2(if_then_else(_Vars, Cond, Then, Else, StoreMap),
+ _GoalInfo, CodeModel, Code) -->
+ ite_gen__generate_ite(CodeModel, Cond, Then, Else, StoreMap, Code).
+code_gen__generate_goal_2(switch(Var, CanFail, CaseList, StoreMap),
+ GoalInfo, CodeModel, Code) -->
+ switch_gen__generate_switch(CodeModel, Var, CanFail, CaseList,
+ StoreMap, GoalInfo, Code).
+code_gen__generate_goal_2(some(_Vars, Goal), _GoalInfo, CodeModel, Code) -->
+ commit_gen__generate_commit(CodeModel, Goal, Code).
+code_gen__generate_goal_2(higher_order_call(PredVar, Args, Types,
+ Modes, Det, _PredOrFunc), GoalInfo, CodeModel, Code) -->
+ call_gen__generate_higher_order_call(CodeModel, PredVar, Args,
Types, Modes, Det, GoalInfo, Code).
-code_gen__generate_semi_goal_2(class_method_call(TCVar, Num, Args, Types, Modes,
- Det), GoalInfo, Code) -->
- call_gen__generate_class_method_call(model_semi, TCVar, Num, Args,
+code_gen__generate_goal_2(class_method_call(TCVar, Num, Args, Types,
+ Modes, Det), GoalInfo, CodeModel, Code) -->
+ call_gen__generate_class_method_call(CodeModel, TCVar, Num, Args,
Types, Modes, Det, GoalInfo, Code).
-code_gen__generate_semi_goal_2(call(PredId, ProcId, Args, BuiltinState, _, _),
- GoalInfo, Code) -->
+code_gen__generate_goal_2(call(PredId, ProcId, Args, BuiltinState, _, _),
+ GoalInfo, CodeModel, Code) -->
(
{ BuiltinState = not_builtin }
->
- code_info__succip_is_used,
- call_gen__generate_call(model_semi, PredId, ProcId, Args,
+ call_gen__generate_call(CodeModel, PredId, ProcId, Args,
GoalInfo, Code)
;
- call_gen__generate_semidet_builtin(PredId, ProcId, Args, Code)
- ).
-code_gen__generate_semi_goal_2(switch(Var, CanFail, CaseList, StoreMap),
- GoalInfo, Instr) -->
- switch_gen__generate_switch(model_semi, Var, CanFail,
- CaseList, StoreMap, GoalInfo, Instr).
-code_gen__generate_semi_goal_2(
- if_then_else(_Vars, CondGoal, ThenGoal, ElseGoal, StoreMap),
- _GoalInfo, Instr) -->
- ite_gen__generate_semidet_ite(CondGoal, ThenGoal, ElseGoal, StoreMap,
- Instr).
-code_gen__generate_semi_goal_2(unify(_L, _R, _U, Uni, _C),
- _GoalInfo, Code) -->
- (
- { Uni = assign(Left, Right) },
- unify_gen__generate_assignment(Left, Right, Code)
- ;
- { Uni = construct(Var, ConsId, Args, Modes) },
- unify_gen__generate_construction(Var, ConsId, Args,
- Modes, Code)
- ;
- { Uni = deconstruct(Var, ConsId, Args, Modes, _) },
- unify_gen__generate_semi_deconstruction(Var, ConsId, Args,
- Modes, Code)
- ;
- { Uni = simple_test(Var1, Var2) },
- unify_gen__generate_test(Var1, Var2, Code)
- ;
- { Uni = complicated_unify(_UniMode, _CanFail) },
- { error("code_gen__generate_semi_goal_2 - complicated_unify") }
+ call_gen__generate_builtin(CodeModel, PredId, ProcId, Args,
+ Code)
).
+code_gen__generate_goal_2(pragma_c_code(MayCallMercury, PredId, ProcId,
+ Args, ArgNames, OrigArgTypes, PragmaImpl),
+ GoalInfo, CodeModel, Code) -->
+ pragma_c_gen__generate_pragma_c_code(CodeModel, MayCallMercury,
+ PredId, ProcId, Args, ArgNames, OrigArgTypes, GoalInfo,
+ PragmaImpl, Code).
-code_gen__generate_semi_goal_2(pragma_c_code(MayCallMercury,
- PredId, ModeId, Args, ArgNames, OrigArgTypes, PragmaCode),
- GoalInfo, Instr) -->
- pragma_c_gen__generate_pragma_c_code(model_semi, MayCallMercury,
- PredId, ModeId, Args, ArgNames, OrigArgTypes, GoalInfo,
- PragmaCode, Instr).
-
-%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
-:- pred code_gen__generate_negation(code_model, hlds_goal, code_tree,
- code_info, code_info).
-:- mode code_gen__generate_negation(in, in, out, in, out) is det.
-
-code_gen__generate_negation(CodeModel, Goal0, Code) -->
- { Goal0 = GoalExpr - GoalInfo0 },
- { goal_info_get_resume_point(GoalInfo0, Resume) },
- (
- { Resume = resume_point(ResumeVarsPrime, ResumeLocsPrime) }
- ->
- { ResumeVars = ResumeVarsPrime},
- { ResumeLocs = ResumeLocsPrime}
- ;
- { error("negated goal has no resume point") }
- ),
- code_info__push_resume_point_vars(ResumeVars),
- % The next line is to enable Goal to pass the
- % pre_goal_update sanity check
- { goal_info_set_resume_point(GoalInfo0, no_resume_point, GoalInfo) },
- { Goal = GoalExpr - GoalInfo },
-
- % for a negated simple test, we can generate better code
- % than the general mechanism, because we don't have to
- % flush the cache.
- (
- { CodeModel = model_semi },
- { GoalExpr = unify(_, _, _, simple_test(L, R), _) },
- code_info__failure_is_direct_branch(CodeAddr),
- code_info__get_globals(Globals),
- { globals__lookup_bool_option(Globals, simple_neg, yes) }
- ->
- % Because we're generating a goal
- % (special-cased, though it may be)
- % we need to apply the pre- and post-
- % updates.
- code_info__pre_goal_update(GoalInfo, yes),
- code_info__produce_variable(L, CodeL, ValL),
- code_info__produce_variable(R, CodeR, ValR),
- code_info__variable_type(L, Type),
- { Type = term__functor(term__atom("string"), [], _) ->
- Op = str_eq
- ; Type = term__functor(term__atom("float"), [], _) ->
- Op = float_eq
- ;
- Op = eq
- },
- { TestCode = node([
- if_val(binop(Op, ValL, ValR), CodeAddr) -
- "test inequality"
- ]) },
- code_info__post_goal_update(GoalInfo),
- { Code = tree(tree(CodeL, CodeR), TestCode) }
- ;
- code_gen__generate_negation_general(CodeModel, Goal,
- ResumeVars, ResumeLocs, Code)
- ),
- code_info__pop_resume_point_vars.
-
-:- pred code_gen__generate_negation_general(code_model, hlds_goal,
- set(var), resume_locs, code_tree, code_info, code_info).
-:- mode code_gen__generate_negation_general(in, in, in, in, out, in, out)
- is det.
-
-code_gen__generate_negation_general(CodeModel, Goal, ResumeVars, ResumeLocs,
- Code) -->
- % This code is a cut-down version of the code for semidet
- % if-then-elses.
-
- code_info__make_known_failure_cont(ResumeVars, ResumeLocs, no,
- ModContCode),
-
- % Maybe save the heap state current before the condition;
- % this ought to be after we make the failure continuation
- % because that causes the cache to get flushed
- code_info__get_globals(Globals),
- {
- globals__lookup_bool_option(Globals,
- reclaim_heap_on_semidet_failure, yes),
- code_util__goal_may_allocate_heap(Goal)
- ->
- ReclaimHeap = yes
- ;
- ReclaimHeap = no
- },
- code_info__maybe_save_hp(ReclaimHeap, SaveHpCode, MaybeHpSlot),
-
- { globals__lookup_bool_option(Globals, use_trail, UseTrail) },
- code_info__maybe_save_ticket(UseTrail, SaveTicketCode,
- MaybeTicketSlot),
-
- % Generate the condition as a semi-deterministic goal;
- % it cannot be nondet, since mode correctness requires it
- % to have no output vars
- code_gen__generate_goal(model_semi, Goal, GoalCode),
-
- ( { CodeModel = model_det } ->
- { DiscardTicketCode = empty },
- { FailCode = empty }
- ;
- code_info__grab_code_info(CodeInfo),
- code_info__pop_failure_cont,
- % The call to reset_ticket(..., commit) here is necessary
- % in order to properly detect floundering.
- code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot,
- commit, DiscardTicketCode),
- code_info__generate_failure(FailCode),
- code_info__slap_code_info(CodeInfo)
- ),
- code_info__restore_failure_cont(RestoreContCode),
- code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot, undo,
- RestoreTicketCode),
- code_info__maybe_restore_and_discard_hp(MaybeHpSlot, RestoreHpCode),
- { Code = tree(ModContCode,
- tree(SaveHpCode,
- tree(SaveTicketCode,
- tree(GoalCode,
- tree(DiscardTicketCode, % is this necessary?
- tree(FailCode,
- tree(RestoreContCode,
- tree(RestoreTicketCode,
- RestoreHpCode)))))))) }.
+% Generate a conjoined series of goals.
+% Note of course, that with a conjunction, state information
+% flows directly from one conjunct to the next.
-%---------------------------------------------------------------------------%
-%---------------------------------------------------------------------------%
+:- pred code_gen__generate_goals(hlds_goals::in, code_model::in,
+ code_tree::out, code_info::in, code_info::out) is det.
-:- pred code_gen__generate_non_goal_2(hlds_goal_expr, hlds_goal_info,
- code_tree, code_info, code_info).
-:- mode code_gen__generate_non_goal_2(in, in, out, in, out) is det.
-
-code_gen__generate_non_goal_2(conj(Goals), _GoalInfo, Code) -->
- code_gen__generate_goals(Goals, model_non, Code).
-code_gen__generate_non_goal_2(par_conj(_Goals, _SM), _GoalInfo, _Code) -->
- % Determinism analysis will report a determinism error if the
- % parallel conj is not det.
- { error("sorry, nondet parallel conjunction not implemented") }.
-code_gen__generate_non_goal_2(some(_Vars, Goal), _GoalInfo, Code) -->
- { Goal = _ - InnerGoalInfo },
- { goal_info_get_code_model(InnerGoalInfo, CodeModel) },
- code_gen__generate_goal(CodeModel, Goal, Code).
-code_gen__generate_non_goal_2(disj(Goals, StoreMap), _GoalInfo, Code) -->
- disj_gen__generate_non_disj(Goals, StoreMap, Code).
-code_gen__generate_non_goal_2(not(_Goal), _GoalInfo, _Code) -->
- { error("Cannot have a nondet negation.") }.
-code_gen__generate_non_goal_2(higher_order_call(PredVar, Args, Types, Modes,
- Det, _PredOrFunc),
- GoalInfo, Code) -->
- call_gen__generate_higher_order_call(model_non, PredVar, Args, Types,
- Modes, Det, GoalInfo, Code).
-code_gen__generate_non_goal_2(class_method_call(TCVar, Num, Args, Types, Modes,
- Det),
- GoalInfo, Code) -->
- call_gen__generate_class_method_call(model_non, TCVar, Num, Args, Types,
- Modes, Det, GoalInfo, Code).
-code_gen__generate_non_goal_2(call(PredId, ProcId, Args, BuiltinState, _, _),
- GoalInfo, Code) -->
+code_gen__generate_goals([], _, empty) --> [].
+code_gen__generate_goals([Goal | Goals], CodeModel, Instr) -->
+ code_gen__generate_goal(CodeModel, Goal, Instr1),
+ code_info__get_instmap(Instmap),
(
- { BuiltinState = not_builtin }
+ { instmap__is_unreachable(Instmap) }
->
- code_info__succip_is_used,
- call_gen__generate_call(model_non, PredId, ProcId, Args,
- GoalInfo, Code)
+ { Instr = Instr1 }
;
- call_gen__generate_nondet_builtin(PredId, ProcId, Args, Code)
+ code_gen__generate_goals(Goals, CodeModel, Instr2),
+ { Instr = tree(Instr1, Instr2) }
).
-code_gen__generate_non_goal_2(switch(Var, CanFail, CaseList, StoreMap),
- GoalInfo, Instr) -->
- switch_gen__generate_switch(model_non, Var, CanFail,
- CaseList, StoreMap, GoalInfo, Instr).
-code_gen__generate_non_goal_2(
- if_then_else(_Vars, CondGoal, ThenGoal, ElseGoal, StoreMap),
- _GoalInfo, Instr) -->
- ite_gen__generate_nondet_ite(CondGoal, ThenGoal, ElseGoal,
- StoreMap, Instr).
-code_gen__generate_non_goal_2(unify(_L, _R, _U, _Uni, _C),
- _GoalInfo, _Code) -->
- { error("Cannot have a nondet unification.") }.
-code_gen__generate_non_goal_2(pragma_c_code(MayCallMercury,
- PredId, ModeId, Args, ArgNames, OrigArgTypes, PragmaCode),
- GoalInfo, Instr) -->
- pragma_c_gen__generate_pragma_c_code(model_non, MayCallMercury,
- PredId, ModeId, Args, ArgNames, OrigArgTypes, GoalInfo,
- PragmaCode, Instr).
%---------------------------------------------------------------------------%
-code_gen__output_args(Args, Vs) :-
- code_gen__select_args_with_mode(Args, top_out, _, Lvals),
- set__list_to_set(Lvals, Vs).
-
-:- pred code_gen__select_args_with_mode(assoc_list(var, arg_info),
- arg_mode, list(var), list(lval)).
-:- mode code_gen__select_args_with_mode(in, in, out, out) is det.
+:- pred code_gen__select_args_with_mode(assoc_list(var, arg_info)::in,
+ arg_mode::in, list(var)::out, list(lval)::out) is det.
code_gen__select_args_with_mode([], _, [], []).
code_gen__select_args_with_mode([Var - ArgInfo | Args], DesiredMode, Vs, Ls) :-
@@ -1194,15 +855,14 @@
Ls = Ls0
).
-
%---------------------------------------------------------------------------%
% Add the succip to the livevals before and after calls.
% Traverses the list of instructions looking for livevals and calls,
% adding succip in the stackvar number given as an argument.
-:- pred code_gen__add_saved_succip(list(instruction), int, list(instruction)).
-:- mode code_gen__add_saved_succip(in, in, out) is det.
+:- pred code_gen__add_saved_succip(list(instruction)::in, int::in,
+ list(instruction)::out) is det.
code_gen__add_saved_succip([], _StackLoc, []).
code_gen__add_saved_succip([Instrn0 - Comment | Instrns0 ], StackLoc,
@@ -1211,7 +871,7 @@
Instrn0 = livevals(LiveVals0),
Instrns0 \= [goto(succip) - _ | _]
% XXX We should also test for tailcalls
- % if we ever start generating them directly.
+ % once we start generating them directly.
->
set__insert(LiveVals0, stackvar(StackLoc), LiveVals1),
Instrn = livevals(LiveVals1)
@@ -1226,5 +886,4 @@
),
code_gen__add_saved_succip(Instrns0, StackLoc, Instrns).
-%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
More information about the developers
mailing list