for review: new method of handling failures, part 5 of 6
Zoltan Somogyi
zs at cs.mu.OZ.AU
Thu Jul 2 16:24:16 AEST 1998
Index: compiler/code_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_util.m,v
retrieving revision 1.98
diff -u -r1.98 code_util.m
--- code_util.m 1998/06/09 02:12:10 1.98
+++ code_util.m 1998/06/09 05:48:45
@@ -18,7 +18,7 @@
:- interface.
:- import_module hlds_module, hlds_pred, hlds_goal, hlds_data, prog_data, llds.
-:- import_module list, std_util, term.
+:- import_module list, assoc_list, set, std_util, term.
% Create a code address which holds the address of the specified
% procedure.
@@ -147,6 +147,11 @@
int, int).
:- mode code_util__count_recursive_calls(in, in, in, out, out) is det.
+ % Return the set of locations occupied by output arguments.
+
+:- pred code_util__output_args(assoc_list(var, arg_info), set(lval)).
+:- mode code_util__output_args(in, out) is det.
+
% These predicates return the set of lvals referenced in an rval
% and an lval respectively. Lvals referenced indirectly through
% lvals of the form var(_) are not counted.
@@ -160,8 +165,10 @@
%---------------------------------------------------------------------------%
:- implementation.
+
:- import_module prog_data, type_util, special_pred.
-:- import_module bool, char, int, string, map, term, varset, require, std_util.
+:- import_module bool, char, int, string, set, map, term, varset.
+:- import_module require, std_util, assoc_list.
%---------------------------------------------------------------------------%
@@ -353,7 +360,8 @@
% --- not yet:
% FullyQualifiedModule = qualified(unqualified("std"), ModuleName),
FullyQualifiedModule = unqualified(ModuleName),
- code_util__translate_builtin_2(ModuleName, PredName, ProcId, Args, _, _).
+ code_util__translate_builtin_2(ModuleName, PredName, ProcId, Args,
+ _, _).
code_util__translate_builtin(FullyQualifiedModule, PredName, ProcId, Args,
BinOp, AsgOp) :-
@@ -881,6 +889,19 @@
int__max(Max0, Max1, Max)
).
+code_util__output_args([], LiveVals) :-
+ set__init(LiveVals).
+code_util__output_args([_V - arg_info(Loc, Mode) | Args], Vs) :-
+ code_util__output_args(Args, Vs0),
+ (
+ Mode = top_out
+ ->
+ code_util__arg_loc_to_register(Loc, Reg),
+ set__insert(Vs0, Reg, Vs)
+ ;
+ Vs = Vs0
+ ).
+
%-----------------------------------------------------------------------------%
code_util__lvals_in_rval(lval(Lval), [Lval | Lvals]) :-
@@ -906,6 +927,8 @@
code_util__lvals_in_lval(maxfr, []).
code_util__lvals_in_lval(curfr, []).
code_util__lvals_in_lval(succip(Rval), Lvals) :-
+ code_util__lvals_in_rval(Rval, Lvals).
+code_util__lvals_in_lval(redofr(Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
code_util__lvals_in_lval(redoip(Rval), Lvals) :-
code_util__lvals_in_rval(Rval, Lvals).
Index: compiler/dense_switch.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dense_switch.m,v
retrieving revision 1.33
diff -u -r1.33 dense_switch.m
--- dense_switch.m 1998/04/08 11:31:31 1.33
+++ dense_switch.m 1998/05/17 03:40:20
@@ -34,9 +34,10 @@
% Generate code for a switch using a dense jump table.
:- pred dense_switch__generate(cases_list, int, int, var, code_model,
- can_fail, store_map, label, code_tree, code_info, code_info).
+ can_fail, store_map, label, branch_end, branch_end, code_tree,
+ code_info, code_info).
:- mode dense_switch__generate(in, in, in, in, in, in, in, in,
- out, in, out) is det.
+ in, out, out, in, out) is det.
% also used by lookup_switch
:- pred dense_switch__calc_density(int, int, int).
@@ -138,7 +139,7 @@
%---------------------------------------------------------------------------%
dense_switch__generate(Cases, StartVal, EndVal, Var, CodeModel, CanFail,
- StoreMap, EndLabel, Code) -->
+ StoreMap, EndLabel, MaybeEnd0, MaybeEnd, 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,
@@ -163,20 +164,14 @@
),
% Now generate the jump table and the cases
dense_switch__generate_cases(Cases, StartVal, EndVal, CodeModel,
- StoreMap, EndLabel, Labels, CasesCode, no,
- MaybeFinalCodeInfo),
+ StoreMap, EndLabel, MaybeEnd0, MaybeEnd,
+ Labels, CasesCode),
+ % XXX
% We keep track of the code_info at the end of one of
% the non-fail cases. We have to do this because
% generating a `fail' slot last would yield the
% wrong liveness and would not unset the failure cont
% for a nondet switch.
- (
- { MaybeFinalCodeInfo = yes(FinalCodeInfo) }
- ->
- code_info__slap_code_info(FinalCodeInfo)
- ;
- { error("dense_switch__generate: no final code_info") }
- ),
{ DoJump = node([
computed_goto(Index, Labels)
- "switch (using dense jump table)"
@@ -185,51 +180,59 @@
{ Code = tree(VarCode, tree(RangeCheck, tree(DoJump, CasesCode))) }.
:- pred dense_switch__generate_cases(cases_list, int, int,
- code_model, store_map, label, list(label), code_tree,
- maybe(code_info), maybe(code_info), code_info, code_info).
-:- mode dense_switch__generate_cases(in, in, in, in, in, in, out, out,
- in, out, in, out) is det.
+ code_model, store_map, label, branch_end, branch_end,
+ list(label), code_tree, code_info, code_info).
+:- mode dense_switch__generate_cases(in, in, in, in, in, in, in, out,
+ out, out, in, out) is det.
dense_switch__generate_cases(Cases0, NextVal, EndVal, CodeModel, StoreMap,
- EndLabel, Labels, Code, MaybeCodeInfo0, MaybeCodeInfo) -->
+ EndLabel, MaybeEnd0, MaybeEnd, Labels, Code) -->
(
{ NextVal > EndVal }
->
- { Code = node([ label(EndLabel) - "End of dense switch" ]) },
+ { MaybeEnd = MaybeEnd0 },
{ Labels = [] },
- { MaybeCodeInfo = MaybeCodeInfo0 }
+ { Code = node([
+ label(EndLabel)
+ - "End of dense switch"
+ ]) }
;
code_info__get_next_label(ThisLabel),
dense_switch__generate_case(Cases0, NextVal, CodeModel,
- StoreMap, Cases1, ThisCode, Comment, MaybeNewCodeInfo),
- { ThisCaseCode = tree(
- node([ label(ThisLabel) - Comment ]),
- tree( ThisCode,
- node([ goto(label(EndLabel))
- - "branch to end of dense switch" ])
- )
- ) },
- { dense_switch__merge_maybe_code_info(MaybeCodeInfo0,
- MaybeNewCodeInfo, MaybeCodeInfo1) },
+ StoreMap, Cases1, MaybeEnd0, MaybeEnd1,
+ ThisCode, Comment),
+ { LabelCode = node([
+ label(ThisLabel)
+ - Comment
+ ]) },
+ { JumpCode = node([
+ goto(label(EndLabel))
+ - "branch to end of dense switch"
+ ]) },
% generate the rest of the cases.
{ NextVal1 is NextVal + 1 },
dense_switch__generate_cases(Cases1, NextVal1, EndVal,
- CodeModel, StoreMap, EndLabel, Labels1, OtherCasesCode,
- MaybeCodeInfo1, MaybeCodeInfo),
+ CodeModel, StoreMap, EndLabel, MaybeEnd1, MaybeEnd,
+ Labels1, OtherCasesCode),
{ Labels = [ThisLabel | Labels1] },
- { Code = tree(ThisCaseCode, OtherCasesCode) }
+ { Code =
+ tree(LabelCode,
+ tree(ThisCode,
+ tree(JumpCode,
+ OtherCasesCode)))
+ }
).
%---------------------------------------------------------------------------%
:- pred dense_switch__generate_case(cases_list, int, code_model, store_map,
- cases_list, code_tree, string, maybe(code_info),
+ cases_list, branch_end, branch_end, code_tree, string,
code_info, code_info).
-:- mode dense_switch__generate_case(in, in, in, in, out, out, out, out,
+:- mode dense_switch__generate_case(in, in, in, in, out, in, out, out, out,
in, out) is det.
dense_switch__generate_case(Cases0, NextVal, CodeModel, StoreMap, Cases,
- Code, Comment, MaybeCodeInfo) -->
+ MaybeEnd0, MaybeEnd, Code, Comment) -->
(
{ Cases0 = [Case | Cases1] },
{ Case = case(_, int_constant(NextVal), _, Goal) }
@@ -237,38 +240,23 @@
{ Comment = "case of dense switch" },
% We need to save the expression cache, etc.,
% and restore them when we've finished.
- code_info__grab_code_info(CodeInfoAtStart),
+ code_info__remember_position(BranchStart),
trace__maybe_generate_internal_event_code(Goal, TraceCode),
code_gen__generate_goal(CodeModel, Goal, GoalCode),
- code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
+ code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd,
+ SaveCode),
{ Code =
tree(TraceCode,
tree(GoalCode,
SaveCode))
},
- code_info__grab_code_info(CodeInfoAtEnd),
- code_info__slap_code_info(CodeInfoAtStart),
- { Cases = Cases1 },
- { MaybeCodeInfo = yes(CodeInfoAtEnd) }
+ code_info__reset_to_position(BranchStart),
+ { Cases = Cases1 }
;
- % This case didn't occur in the original case list - just
- % generate a `fail' for it.
+ % This case didn't occur in the original case list
+ % - just generate a `fail' for it.
{ Comment = "compiler-introduced `fail' case of dense switch" },
code_info__generate_failure(Code),
- { Cases = Cases0 },
- { MaybeCodeInfo = no }
- ).
-
-:- pred dense_switch__merge_maybe_code_info(maybe(code_info),
- maybe(code_info), maybe(code_info)).
-:- mode dense_switch__merge_maybe_code_info(in, in, out) is det.
-
-dense_switch__merge_maybe_code_info(CodeInfo0, CodeInfo1, CodeInfo) :-
- (
- CodeInfo0 = no
- ->
- CodeInfo = CodeInfo1
- ;
- CodeInfo = CodeInfo0
+ { MaybeEnd = MaybeEnd0 },
+ { Cases = Cases0 }
).
-
Index: compiler/disj_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/disj_gen.m,v
retrieving revision 1.64
diff -u -r1.64 disj_gen.m
--- disj_gen.m 1998/06/02 05:31:36 1.64
+++ disj_gen.m 1998/06/23 02:21:40
@@ -10,9 +10,6 @@
%
% The predicates of this module generate code for disjunctions.
%
-% The handling of model_det and model_semi disjunctions is almost identical.
-% The handling of model_non disjunctions is also quite similar.
-%
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
@@ -23,97 +20,143 @@
:- import_module hlds_goal, llds, code_info.
:- import_module list.
-:- pred disj_gen__generate_det_disj(list(hlds_goal), store_map,
- code_tree, code_info, code_info).
-:- mode disj_gen__generate_det_disj(in, in, out, in, out) is det.
-
-:- pred disj_gen__generate_semi_disj(list(hlds_goal), store_map,
- code_tree, code_info, code_info).
-:- mode disj_gen__generate_semi_disj(in, in, out, in, out) is det.
-
-:- pred disj_gen__generate_non_disj(list(hlds_goal), store_map,
- code_tree, code_info, code_info).
-:- mode disj_gen__generate_non_disj(in, in, out, in, out) is det.
+:- pred disj_gen__generate_disj(code_model::in, list(hlds_goal)::in,
+ store_map::in, code_tree::out, code_info::in, code_info::out) is det.
%---------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_data, code_gen, code_util, trace, options, globals.
-:- import_module bool, set, tree, map, std_util, require.
+:- import_module bool, set, tree, map, std_util, term, require.
-%---------------------------------------------------------------------------%
-
-disj_gen__generate_det_disj(Goals, StoreMap, Code) -->
- disj_gen__generate_pruned_disj(Goals, StoreMap, Code).
-
-disj_gen__generate_semi_disj(Goals, StoreMap, Code) -->
- ( { Goals = [] } ->
- code_info__generate_failure(Code)
+disj_gen__generate_disj(CodeModel, Goals, StoreMap, Code) -->
+ (
+ { Goals = [] },
+ ( { CodeModel = model_semi } ->
+ code_info__generate_failure(Code)
+ ;
+ { error("empty disjunction") }
+ )
;
- disj_gen__generate_pruned_disj(Goals, StoreMap, Code)
+ { Goals = [Goal | _] },
+ { Goal = _ - GoalInfo },
+ { goal_info_get_resume_point(GoalInfo, Resume) },
+ { Resume = resume_point(ResumeVarsPrime, _) ->
+ ResumeVars = ResumeVarsPrime
+ ;
+ set__init(ResumeVars)
+ },
+ disj_gen__generate_real_disj(CodeModel, ResumeVars,
+ Goals, StoreMap, Code)
).
%---------------------------------------------------------------------------%
-:- pred disj_gen__generate_pruned_disj(list(hlds_goal), store_map,
- code_tree, code_info, code_info).
-:- mode disj_gen__generate_pruned_disj(in, in, out, in, out) is det.
+:- pred disj_gen__generate_real_disj(code_model::in, set(var)::in,
+ list(hlds_goal)::in, store_map::in, code_tree::out,
+ code_info::in, code_info::out) is det.
+
+disj_gen__generate_real_disj(CodeModel, ResumeVars, Goals, StoreMap, Code) -->
+ % Make sure that the variables whose values will be needed
+ % on backtracking to any disjunct are materialized into
+ % registers or stack slots. Their locations are recorded
+ % in ResumeMap.
+ code_info__produce_vars(ResumeVars, ResumeMap, FlushCode),
-disj_gen__generate_pruned_disj(Goals, StoreMap, Code) -->
% If we are using a trail, save the current trail state
% before the first disjunct.
+ % XXX We should use a scheme such as the one we use for heap
+ % recovery for semi and det disjunctions, and delay saving
+ % the ticket until necessary.
code_info__get_globals(Globals),
- { globals__lookup_bool_option(Globals, reclaim_heap_on_semidet_failure,
- ReclaimHeap) },
{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
code_info__maybe_save_ticket(UseTrail, SaveTicketCode,
MaybeTicketSlot),
- % Rather than saving the heap pointer here,
- % we delay saving it until we get to the first
- % disjunct that might allocate some heap space.
- { MaybeHpSlot = no },
+ % If we are using a grade in which we can recover memory
+ % by saving and restoring the heap pointer, set up for
+ % doing so if necessary.
+ ( { CodeModel = model_non } ->
+ % With nondet disjunctions, we must recover memory
+ % across all disjuncts, even disjuncts that cannot
+ % themselves allocate memory, since we can backtrack
+ % to disjunct N after control leaves disjunct N-1.
+ { globals__lookup_bool_option(Globals,
+ reclaim_heap_on_nondet_failure, ReclaimHeap) },
+ code_info__maybe_save_hp(ReclaimHeap, SaveHpCode,
+ MaybeHpSlot)
+ ;
+ % With other disjunctions, we can backtrack to
+ % disjunct N only from disjunct N-1, so if disjunct
+ % N-1 does not allocate memory, we need not recover
+ % memory across it. Since it is possible (and common)
+ % for no disjunct to allocate memory, we delay saving
+ % the heap pointer and allocating a stack slot for
+ % the saved hp as long as possible.
+ { globals__lookup_bool_option(Globals,
+ reclaim_heap_on_semidet_failure, ReclaimHeap) },
+ { SaveHpCode = empty },
+ { MaybeHpSlot = no }
+ ),
+
+ % Save the values of any stack slots we may hijack,
+ % and if necessary, set the redofr slot of the top frame
+ % to point to this frame.
+ code_info__prepare_for_disj_hijack(CodeModel,
+ HijackInfo, PrepareHijackCode),
- % Generate all the disjuncts.
code_info__get_next_label(EndLabel),
- disj_gen__generate_pruned_disjuncts(Goals, StoreMap, EndLabel,
- ReclaimHeap, MaybeHpSlot, MaybeTicketSlot, no, GoalsCode),
-
- % Remake the code_info using the store map for the
- % variable locations at the end of the disjunction.
- code_info__remake_with_store_map(StoreMap),
- { Code = tree(SaveTicketCode, GoalsCode) }.
+ code_info__remember_position(BranchStart),
+ disj_gen__generate_disjuncts(Goals, CodeModel, ResumeMap, no,
+ HijackInfo, StoreMap, EndLabel,
+ ReclaimHeap, MaybeHpSlot, MaybeTicketSlot,
+ BranchStart, no, MaybeEnd, GoalsCode),
+
+ code_info__after_all_branches(StoreMap, MaybeEnd),
+ ( { CodeModel = model_non } ->
+ code_info__set_resume_point_to_unknown
+ ;
+ []
+ ),
+ % XXX release any temp slots holding heap or trail pointers
+ { Code =
+ tree(FlushCode,
+ tree(SaveTicketCode,
+ tree(SaveHpCode,
+ tree(PrepareHijackCode,
+ GoalsCode))))
+ }.
%---------------------------------------------------------------------------%
-:- pred disj_gen__generate_pruned_disjuncts(list(hlds_goal), store_map,
- label, bool, maybe(lval), maybe(lval), bool, code_tree,
- code_info, code_info).
-:- mode disj_gen__generate_pruned_disjuncts(in, in, in, in, in, in, in,
- out, in, out) is det.
-
- % To generate code for a det or semidet disjunction,
- % we generate a chain of goals if-then-else style
- % until we come to a goal without a resume point.
- % That goal is the last in the chain that we need to
- % generate code for. (This is figured out by the liveness pass.)
- %
- % For a semidet disj, this goal will be semidet,
- % and will be followed by no other goal.
- % For a det disj, this goal will be det,
- % and may be followed by other goals.
- %
- % XXX For efficiency, we ought not to restore anything in the
- % first disjunct.
-
-disj_gen__generate_pruned_disjuncts([], _, _, _, _, _, _, _) -->
- { error("Empty pruned disjunction!") }.
-disj_gen__generate_pruned_disjuncts([Goal0 | Goals], StoreMap, EndLabel,
- ReclaimHeap, MaybeHpSlot0, MaybeTicketSlot, First, Code) -->
+:- pred disj_gen__generate_disjuncts(list(hlds_goal)::in,
+ code_model::in, resume_map::in, maybe(resume_point_info)::in,
+ disj_hijack_info::in, store_map::in, label::in,
+ bool::in, maybe(lval)::in, maybe(lval)::in, position_info::in,
+ maybe(branch_end_info)::in, maybe(branch_end_info)::out,
+ code_tree::out, code_info::in, code_info::out) is det.
+
+disj_gen__generate_disjuncts([], _, _, _, _, _, _, _, _, _, _, _, _, _) -->
+ { error("empty disjunction!") }.
+disj_gen__generate_disjuncts([Goal0 | Goals], CodeModel, FullResumeMap,
+ MaybeEntryResumePoint, HijackInfo, StoreMap, EndLabel,
+ ReclaimHeap, MaybeHpSlot0, MaybeTicketSlot,
+ BranchStart, MaybeEnd0, MaybeEnd, Code) -->
+
+ code_info__reset_to_position(BranchStart),
+
+ % If this is not the first disjunct, generate the
+ % resume point by which arrive at this disjunct.
+ ( { MaybeEntryResumePoint = yes(EntryResumePoint) } ->
+ code_info__generate_resume_point(EntryResumePoint,
+ EntryResumePointCode)
+ ;
+ { EntryResumePointCode = empty }
+ ),
+
{ Goal0 = GoalExpr0 - GoalInfo0 },
- { goal_info_get_code_model(GoalInfo0, CodeModel) },
{ goal_info_get_resume_point(GoalInfo0, Resume) },
(
{ Resume = resume_point(ResumeVars, ResumeLocs) }
@@ -121,30 +164,28 @@
% Emit code for a non-last disjunct, including setting things
% up for the execution of the next disjunct.
- code_info__push_resume_point_vars(ResumeVars),
- code_info__make_known_failure_cont(ResumeVars, ResumeLocs, no,
- ModContCode),
- % 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 = GoalExpr0 - GoalInfo },
-
- ( { First = no } ->
+ ( { MaybeEntryResumePoint = yes(_) } ->
% Reset the heap pointer to recover memory
% allocated by the previous disjunct(s),
% if necessary.
code_info__maybe_restore_hp(MaybeHpSlot0,
- RestoreHPCode),
+ RestoreHpCode),
% Reset the solver state if necessary.
code_info__maybe_reset_ticket(MaybeTicketSlot, undo,
RestoreTicketCode)
;
- { RestoreHPCode = empty },
+ { RestoreHpCode = empty },
{ RestoreTicketCode = empty }
),
+ % The pre_goal_update sanity check insist on
+ % no_resume_point, to make sure that all resume
+ % points have been handled by surrounding code.
+ { goal_info_set_resume_point(GoalInfo0, no_resume_point,
+ GoalInfo) },
+ { Goal = GoalExpr0 - GoalInfo },
+
% Save hp if it needs to be saved and hasn't been
% saved previously.
(
@@ -152,244 +193,109 @@
{ code_util__goal_may_allocate_heap(Goal) },
{ MaybeHpSlot0 = no }
->
- code_info__save_hp(SaveHPCode, HpSlot),
+ code_info__save_hp(SaveHpCode, HpSlot),
{ MaybeHpSlot = yes(HpSlot) }
;
- { SaveHPCode = empty },
+ { SaveHpCode = empty },
{ MaybeHpSlot = MaybeHpSlot0 }
),
- code_info__grab_code_info(CodeInfo),
-
- % Generate the disjunct as a semi-deterministic goal.
- { CodeModel = model_semi ->
- true
- ;
- error("pruned disj non-last goal is not semidet")
- },
- trace__maybe_generate_internal_event_code(Goal, TraceCode),
- code_gen__generate_goal(CodeModel, Goal, GoalCode),
- code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
-
- { BranchCode = node([
- goto(label(EndLabel)) -
- "skip to end of pruned disj"
- ]) },
-
- code_info__slap_code_info(CodeInfo),
- code_info__pop_resume_point_vars,
- code_info__restore_failure_cont(RestoreContCode),
-
- disj_gen__generate_pruned_disjuncts(Goals, StoreMap, EndLabel,
- ReclaimHeap, MaybeHpSlot, MaybeTicketSlot, no,
- RestCode),
-
- { Code = tree(ModContCode,
- tree(RestoreHPCode,
- tree(SaveHPCode,
- tree(RestoreTicketCode,
- tree(TraceCode,
- tree(GoalCode,
- tree(SaveCode,
- tree(BranchCode,
- tree(RestoreContCode,
- RestCode)))))))))
- }
- ;
- % Emit code for the last disjunct.
-
- % Restore the heap pointer if necessary.
- code_info__maybe_restore_and_discard_hp(MaybeHpSlot0,
- RestoreHPCode),
-
- % Restore the solver state if necessary.
- code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot,
- undo, RestorePopTicketCode),
-
- % Generate the goal.
- trace__maybe_generate_internal_event_code(Goal0, TraceCode),
- code_gen__generate_goal(CodeModel, Goal0, GoalCode),
- code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
-
- { EndCode = node([
- label(EndLabel) - "End of pruned disj"
- ]) },
- { Code = tree(RestoreHPCode,
- tree(RestorePopTicketCode,
- tree(TraceCode,
- tree(GoalCode,
- tree(SaveCode,
- EndCode)))))
- }
- ).
-
-%---------------------------------------------------------------------------%
-
-disj_gen__generate_non_disj(Goals, StoreMap, Code) -->
-
- % Sanity check
- {
- Goals = [],
- error("empty disjunction shouldn't be nondet")
- ;
- Goals = [_],
- error("singleton disjunction")
- ;
- Goals = [_, _ | _]
- },
-
- % If we are using a trail, save the current trail state
- % before the first disjunct.
- code_info__get_globals(Globals),
- { globals__lookup_bool_option(Globals, use_trail, UseTrail) },
- code_info__maybe_save_ticket(UseTrail, SaveTicketCode,
- MaybeTicketSlot),
-
- % With nondet disjunctions, we must recover memory across
- % all disjuncts, since we can backtract to disjunct N
- % even after control leaves disjunct N-1.
- { globals__lookup_bool_option(Globals, reclaim_heap_on_nondet_failure,
- ReclaimHeap) },
- code_info__maybe_save_hp(ReclaimHeap, SaveHeapCode, MaybeHpSlot),
-
- code_info__get_next_label(EndLabel),
- disj_gen__generate_non_disjuncts(Goals, StoreMap, EndLabel,
- MaybeHpSlot, MaybeTicketSlot, no, GoalsCode),
-
- % since we don't know which disjunct we have come from
- % we must set the current failure continuation to unknown.
-
- code_info__unset_failure_cont(FlushResumeVarsCode),
- code_info__remake_with_store_map(StoreMap),
- { Code = tree(SaveTicketCode,
- tree(SaveHeapCode,
- tree(GoalsCode,
- FlushResumeVarsCode))) }.
-
-%---------------------------------------------------------------------------%
-
- % XXX For efficiency, we ought not to restore anything in the
- % first disjunct.
-
-:- pred disj_gen__generate_non_disjuncts(list(hlds_goal), store_map, label,
- maybe(lval), maybe(lval), bool, code_tree, code_info, code_info).
-:- mode disj_gen__generate_non_disjuncts(in, in, in, in, in, in,
- out, in, out) is det.
-
-disj_gen__generate_non_disjuncts([], _, _, _, _, _, _) -->
- { error("empty nondet disjunction!") }.
-disj_gen__generate_non_disjuncts([Goal0 | Goals], StoreMap, EndLabel,
- MaybeHpSlot, MaybeTicketSlot, First, Code) -->
-
- { Goal0 = GoalExpr0 - GoalInfo0 },
- { goal_info_get_resume_point(GoalInfo0, Resume) },
- (
- { Resume = resume_point(ResumeVars, ResumeLocs) }
- ->
- % Emit code for a non-last disjunct, including setting things
- % up for the execution of the next disjunct.
-
- code_info__push_resume_point_vars(ResumeVars),
- code_info__make_known_failure_cont(ResumeVars, ResumeLocs, yes,
+ code_info__make_resume_point(ResumeVars, ResumeLocs,
+ FullResumeMap, NextResumePoint),
+ code_info__effect_resume_point(NextResumePoint, CodeModel,
ModContCode),
- % 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 = GoalExpr0 - GoalInfo },
- ( { First = no } ->
- % Reset the heap pointer to recover memory
- % allocated by the previous disjunct(s),
- % if necessary.
- code_info__maybe_restore_hp(MaybeHpSlot,
- RestoreHPCode),
+ trace__maybe_generate_internal_event_code(Goal, TraceCode),
+ { goal_info_get_code_model(GoalInfo, GoalCodeModel) },
+ code_gen__generate_goal(GoalCodeModel, Goal, GoalCode),
- % Reset the solver state if necessary.
- code_info__maybe_reset_ticket(MaybeTicketSlot, undo,
- RestoreTicketCode)
+ ( { CodeModel = model_non } ->
+ % We can backtrack to the next disjunct from outside,
+ % so we make sure every variable in the resume set
+ % is in its stack slot.
+ code_info__flush_resume_vars_to_stack(ResumeVarsCode)
;
- { RestoreHPCode = empty },
- { RestoreTicketCode = empty }
+ { ResumeVarsCode = empty }
),
- code_info__grab_code_info(CodeInfo),
-
- trace__maybe_generate_internal_event_code(Goal, TraceCode),
- code_gen__generate_goal(model_non, Goal, GoalCode),
- code_info__generate_branch_end(model_non, StoreMap, SaveCode),
-
- % Make sure every variable in the resume set is in its
- % stack slot.
- code_info__flush_resume_vars_to_stack(FlushResumeVarsCode),
+ % Put every variable whose value is needed after
+ % the disjunction to the place indicated by StoreMap,
+ % and accumulate information about the code_info state
+ % at the ends of the branches so far.
+ code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd1,
+ SaveCode),
{ BranchCode = node([
goto(label(EndLabel)) -
"skip to end of nondet disj"
]) },
- code_info__slap_code_info(CodeInfo),
- code_info__pop_resume_point_vars,
-
- % Make sure that the redoip of the top nondet frame
- % points to the right label, and set up the start of
- % the next disjunct.
- code_info__restore_failure_cont(RestoreContCode),
-
- disj_gen__generate_non_disjuncts(Goals, StoreMap, EndLabel,
- MaybeHpSlot, MaybeTicketSlot, no, RestCode),
-
- { Code = tree(ModContCode,
- tree(RestoreHPCode,
- tree(RestoreTicketCode,
- tree(TraceCode,
- tree(GoalCode,
- tree(SaveCode,
- tree(FlushResumeVarsCode,
- tree(BranchCode,
- tree(RestoreContCode,
- RestCode)))))))))
+ disj_gen__generate_disjuncts(Goals, CodeModel, FullResumeMap,
+ yes(NextResumePoint), HijackInfo, StoreMap, EndLabel,
+ ReclaimHeap, MaybeHpSlot, MaybeTicketSlot,
+ BranchStart, MaybeEnd1, MaybeEnd, RestCode),
+
+ { Code =
+ tree(EntryResumePointCode,
+ tree(RestoreHpCode,
+ tree(RestoreTicketCode,
+ tree(SaveHpCode,
+ tree(ModContCode,
+ tree(TraceCode,
+ tree(GoalCode,
+ tree(ResumeVarsCode,
+ tree(SaveCode,
+ tree(BranchCode,
+ RestCode))))))))))
}
;
- % Emit code for the last disjunct.
+ % Emit code for the last disjunct
- { Goals = [] ->
- true
+ % Restore the heap pointer and solver state
+ % if necessary.
+ ( { CodeModel = model_non } ->
+
+ % Note that we can't release the temps used for the
+ % heap pointer and ticket, because those values may be
+ % required again after backtracking after control
+ % leaves the disjunction. If we were to reuse either
+ % of their stack slots for something else when
+ % generating the code that follows this goal,
+ % then the values that earlier disjuncts need on
+ % backtracking would get clobbered.
+ % Thus we must not use the `_discard' versions
+ % of the two predicates below.
+
+ code_info__maybe_restore_hp(MaybeHpSlot0,
+ RestoreHpCode),
+ code_info__maybe_reset_and_pop_ticket(
+ MaybeTicketSlot, undo, RestoreTicketCode)
;
- error("disj_gen__generate_non_disjuncts: last disjunct followed by others")
- },
+ code_info__maybe_restore_and_discard_hp(MaybeHpSlot0,
+ RestoreHpCode),
+ code_info__maybe_reset_and_discard_ticket(
+ MaybeTicketSlot, undo, RestoreTicketCode)
+ ),
- % Note that we can't release the temps used for the heap
- % pointer and ticket, because those values may be required
- % again after backtracking from goals that following
- % the disjunction.
- % If we were to reuse the same stack slot for something
- % else when generating the code that follows this goal,
- % then the values that earlier disjuncts need on
- % backtracking would get clobbered.
- % Thus we must not use the `_discard' versions of the two
- % predicates below.
-
- % Restore the heap pointer if necessary.
- code_info__maybe_restore_hp(MaybeHpSlot, RestoreHPCode),
-
- % Restore the solver state if necessary.
- code_info__maybe_reset_and_pop_ticket(
- MaybeTicketSlot, undo, RestorePopTicketCode),
+ code_info__undo_disj_hijack(HijackInfo, UndoCode),
trace__maybe_generate_internal_event_code(Goal0, TraceCode),
- code_gen__generate_goal(model_non, Goal0, GoalCode),
- code_info__generate_branch_end(model_non, StoreMap, SaveCode),
+ code_gen__generate_goal(CodeModel, Goal0, GoalCode),
+ code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd,
+ SaveCode),
{ EndCode = node([
label(EndLabel) - "End of nondet disj"
]) },
- { Code = tree(RestoreHPCode,
- tree(RestorePopTicketCode,
- tree(TraceCode,
- tree(GoalCode,
- tree(SaveCode,
- EndCode)))))
+ { Code =
+ tree(EntryResumePointCode,
+ tree(TraceCode,
+ tree(RestoreHpCode,
+ tree(RestoreTicketCode,
+ tree(UndoCode,
+ tree(GoalCode,
+ tree(SaveCode,
+ EndCode)))))))
}
).
Index: compiler/dupelim.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dupelim.m,v
retrieving revision 1.33
diff -u -r1.33 dupelim.m
--- dupelim.m 1998/06/09 02:12:32 1.33
+++ dupelim.m 1998/06/29 08:26:46
@@ -294,7 +294,7 @@
Instr1 = call(_, _, _, _),
Instr = Instr1
;
- Instr1 = mkframe(_, _, _, _),
+ Instr1 = mkframe(_, _),
Instr = Instr1
;
Instr1 = modframe(_),
@@ -415,6 +415,9 @@
Lval1 = succfr(_),
Lval = Lval1
;
+ Lval1 = redofr(_),
+ Lval = Lval1
+ ;
Lval1 = prevfr(_),
Lval = Lval1
;
@@ -562,7 +565,7 @@
Instr2 = Instr1,
Instr = Instr1
;
- Instr1 = mkframe(_, _, _, _),
+ Instr1 = mkframe(_, _),
Instr2 = Instr1,
Instr = Instr1
;
@@ -695,6 +698,10 @@
Lval2 = Lval1,
Lval = Lval1
;
+ Lval1 = redofr(_),
+ Lval2 = Lval1,
+ Lval = Lval1
+ ;
Lval1 = succfr(_),
Lval2 = Lval1,
Lval = Lval1
@@ -793,8 +800,8 @@
dupelim__replace_labels_instr(call(Target, Return0, LiveInfo, CM),
ReplMap, call(Target, Return, LiveInfo, CM)) :-
dupelim__replace_labels_code_addr(Return0, ReplMap, Return).
-dupelim__replace_labels_instr(mkframe(Name, Size, Pragma, Redoip0), ReplMap,
- mkframe(Name, Size, Pragma, Redoip)) :-
+dupelim__replace_labels_instr(mkframe(NondetFrameInfo, Redoip0), ReplMap,
+ mkframe(NondetFrameInfo, Redoip)) :-
dupelim__replace_labels_code_addr(Redoip0, ReplMap, Redoip).
dupelim__replace_labels_instr(modframe(Redoip0), ReplMap, modframe(Redoip)) :-
dupelim__replace_labels_code_addr(Redoip0, ReplMap, Redoip).
@@ -874,6 +881,8 @@
dupelim__replace_labels_lval(succip(Rval0), ReplMap, succip(Rval)) :-
dupelim__replace_labels_rval(Rval0, ReplMap, Rval).
dupelim__replace_labels_lval(redoip(Rval0), ReplMap, redoip(Rval)) :-
+ dupelim__replace_labels_rval(Rval0, ReplMap, Rval).
+dupelim__replace_labels_lval(redofr(Rval0), ReplMap, redofr(Rval)) :-
dupelim__replace_labels_rval(Rval0, ReplMap, Rval).
dupelim__replace_labels_lval(succfr(Rval0), ReplMap, succfr(Rval)) :-
dupelim__replace_labels_rval(Rval0, ReplMap, Rval).
Index: compiler/exprn_aux.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/exprn_aux.m,v
retrieving revision 1.28
diff -u -r1.28 exprn_aux.m
--- exprn_aux.m 1998/01/23 12:56:29 1.28
+++ exprn_aux.m 1998/02/27 02:24:10
@@ -319,6 +319,8 @@
exprn_aux__vars_in_rval(Rval, Vars).
exprn_aux__vars_in_lval(redoip(Rval), Vars) :-
exprn_aux__vars_in_rval(Rval, Vars).
+exprn_aux__vars_in_lval(redofr(Rval), Vars) :-
+ exprn_aux__vars_in_rval(Rval, Vars).
exprn_aux__vars_in_lval(succfr(Rval), Vars) :-
exprn_aux__vars_in_rval(Rval, Vars).
exprn_aux__vars_in_lval(prevfr(Rval), Vars) :-
@@ -469,6 +471,11 @@
Rval0, Rval),
Lval = redoip(Rval)
;
+ Lval0 = redofr(Rval0),
+ exprn_aux__substitute_lval_in_rval(OldLval, NewLval,
+ Rval0, Rval),
+ Lval = redofr(Rval)
+ ;
Lval0 = succfr(Rval0),
exprn_aux__substitute_lval_in_rval(OldLval, NewLval,
Rval0, Rval),
@@ -618,6 +625,11 @@
Rval0, Rval),
Lval = redoip(Rval)
;
+ Lval0 = redofr(Rval0),
+ exprn_aux__substitute_rval_in_rval(OldRval, NewRval,
+ Rval0, Rval),
+ Lval = redofr(Rval)
+ ;
Lval0 = succfr(Rval0),
exprn_aux__substitute_rval_in_rval(OldRval, NewRval,
Rval0, Rval),
@@ -817,6 +829,8 @@
exprn_aux__lval_addrs(prevfr(Rval), CodeAddrs, DataAddrs) :-
exprn_aux__rval_addrs(Rval, CodeAddrs, DataAddrs).
exprn_aux__lval_addrs(succfr(Rval), CodeAddrs, DataAddrs) :-
+ exprn_aux__rval_addrs(Rval, CodeAddrs, DataAddrs).
+exprn_aux__lval_addrs(redofr(Rval), CodeAddrs, DataAddrs) :-
exprn_aux__rval_addrs(Rval, CodeAddrs, DataAddrs).
exprn_aux__lval_addrs(redoip(Rval), CodeAddrs, DataAddrs) :-
exprn_aux__rval_addrs(Rval, CodeAddrs, DataAddrs).
Index: compiler/frameopt.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/frameopt.m,v
retrieving revision 1.70
diff -u -r1.70 frameopt.m
--- frameopt.m 1998/06/09 02:12:40 1.70
+++ frameopt.m 1998/06/29 08:19:37
@@ -533,7 +533,7 @@
(
Uinstr = call(_, _, _, _)
;
- Uinstr = mkframe(_, _, _, _)
+ Uinstr = mkframe(_, _)
;
Uinstr = c_code(_)
;
@@ -666,7 +666,7 @@
;
Labels = []
).
-possible_targets(mkframe(_, _, _, _), []).
+possible_targets(mkframe(_, _), []).
possible_targets(modframe(_), []).
possible_targets(label(_), []).
possible_targets(goto(CodeAddr), Targets) :-
@@ -1274,8 +1274,8 @@
;
ReturnAddr = ReturnAddr0
).
-substitute_labels_instr(mkframe(Name, Size, Pragma, Redoip), _,
- mkframe(Name, Size, Pragma, Redoip)).
+substitute_labels_instr(mkframe(NondetFrameInfo, Redoip), _,
+ mkframe(NondetFrameInfo, Redoip)).
substitute_labels_instr(modframe(Redoip), _, modframe(Redoip)).
substitute_labels_instr(label(_), _, _) :-
error("label in substitute_labels_instr").
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.58
diff -u -r1.58 handle_options.m
--- handle_options.m 1998/07/01 06:08:24 1.58
+++ handle_options.m 1998/07/01 12:36:09
@@ -135,14 +135,14 @@
->
{ map__lookup(OptionTable,
fact_table_hash_percent_full, PercentFull) },
- (
+ (
{ PercentFull = int(Percent) },
{ Percent >= 1 },
{ Percent =< 100 }
->
{ map__lookup(OptionTable, termination_norm,
TermNorm0) },
- (
+ (
{ TermNorm0 = string(TermNormStr) },
{ convert_termination_norm(TermNormStr, TermNorm) }
->
@@ -181,7 +181,7 @@
{ Error = yes("Invalid GC option (must be `none', `conservative' or `accurate')") }
).
-:- pred postprocess_options_2(option_table, gc_method, tags_method,
+:- pred postprocess_options_2(option_table, gc_method, tags_method,
args_method, prolog_dialect, termination_norm, trace_level,
io__state, io__state).
:- mode postprocess_options_2(in, in, in, in, in, in, in, di, uo) is det.
@@ -225,7 +225,7 @@
{ NumTagBits0 = -1 }
->
globals__io_lookup_int_option(conf_low_tag_bits, NumTagBits1)
- ;
+ ;
{ NumTagBits1 = NumTagBits0 }
),
@@ -264,12 +264,12 @@
% --split-c-files implies --procs-per-c-function 1
option_implies(split_c_files, procs_per_c_function, int(1)),
- % -D all is really -D "abcdefghijklmnopqrstuvwxyz"
+ % -D all is really "all possible flag chars are in VerboseDump"
globals__io_lookup_string_option(verbose_dump_hlds, VerboseDump),
( { VerboseDump = "all" } ->
globals__io_set_option(verbose_dump_hlds,
string("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"))
- ;
+ ;
[]
),
@@ -290,8 +290,8 @@
[]
),
- % Tracing requires
- % - disabling optimizations that would change
+ % Execution tracing requires
+ % - disabling optimizations that would change
% the trace being generated
% - enabling some low level optimizations to ensure consistent
% paths across optimization levels
@@ -350,11 +350,12 @@
option_implies(trace_stack_layout, procid_stack_layout, bool(yes)),
% --gc accurate requires `agc' stack layouts, typeinfo liveness,
- % and needs frameopt to be switched off.
+ % and needs hijacks and frameopt to be switched off.
( { GC_Method = accurate } ->
globals__io_set_option(agc_stack_layout, bool(yes)),
globals__io_set_option(typeinfo_liveness, bool(yes)),
- globals__io_set_option(optimize_frames, bool(no))
+ globals__io_set_option(allow_hijacks, bool(no)),
+ globals__io_set_option(optimize_frames, bool(no))
;
[]
),
@@ -384,7 +385,7 @@
% --intermod-unused-args implies --intermodule-optimization and
% --optimize-unused-args.
- option_implies(intermod_unused_args, intermodule_optimization,
+ option_implies(intermod_unused_args, intermodule_optimization,
bool(yes)),
option_implies(intermod_unused_args, optimize_unused_args, bool(yes)),
@@ -426,8 +427,9 @@
% option_implies(SourceBoolOption, ImpliedOption, ImpliedOptionValue, IO0, IO).
% If the SourceBoolOption is set to yes, then the ImpliedOption is set
% to ImpliedOptionValue.
-:- pred option_implies(option::in, option::in, option_data::in,
+:- pred option_implies(option::in, option::in, option_data::in,
io__state::di, io__state::uo) is det.
+
option_implies(SourceOption, ImpliedOption, ImpliedOptionValue) -->
globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
( { SourceOptionValue = yes } ->
@@ -436,12 +438,13 @@
[]
).
-% option_neg_implies(SourceBoolOption, ImpliedOption,
+% option_neg_implies(SourceBoolOption, ImpliedOption,
% ImpliedOptionValue, IO0, IO).
% If the SourceBoolOption is set to no, then the ImpliedOption is set
% to ImpliedOptionValue.
-:- pred option_neg_implies(option::in, option::in, option_data::in,
+:- pred option_neg_implies(option::in, option::in, option_data::in,
io__state::di, io__state::uo) is det.
+
option_neg_implies(SourceOption, ImpliedOption, ImpliedOptionValue) -->
globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
( { SourceOptionValue = no } ->
@@ -509,14 +512,14 @@
( ProfileCalls = yes ->
( ProfileMemory = yes ->
Part4 = ".profall"
- ;
+ ;
Part4 = ".prof"
)
;
( ProfileMemory = yes ->
Part4 = ".profmemtime" /* not allowed */
/* `ml' will catch the error */
- ;
+ ;
Part4 = ".proftime" /* currently useless */
)
)
@@ -524,14 +527,14 @@
( ProfileCalls = yes ->
( ProfileMemory = yes ->
Part4 = ".memprof"
- ;
+ ;
Part4 = ".profcalls"
)
- ;
+ ;
( ProfileMemory = yes ->
Part4 = ".profmem" /* not allowed */
/* `ml' will catch the error */
- ;
+ ;
Part4 = ""
)
)
@@ -550,8 +553,6 @@
string__format(".hightags%d", [i(TagBits)], Part6)
;
string__format(".tags%d", [i(TagBits)], Part6)
- ;
-
),
( UnboxedFloat = yes ->
Part7 = ".ubf"
@@ -688,10 +689,10 @@
),
% Set the type of gc that the grade option implies.
% 'accurate' is now set in the grade, so we can override it here.
- (
- { GC = accurate },
+ (
+ { GC = accurate },
set_string_opt(gc, "accurate")
- ;
+ ;
{ GC = conservative },
set_string_opt(gc, "conservative")
;
Index: compiler/hlds_module.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_module.m,v
retrieving revision 1.34
diff -u -r1.34 hlds_module.m
--- hlds_module.m 1998/05/07 06:41:03 1.34
+++ hlds_module.m 1998/07/01 05:57:10
@@ -162,7 +162,7 @@
module_info).
:- mode module_info_set_superclasses(in, in, out) is det.
- % The cell count is used as a unique label number for
+ % The cell count is used as a unique cell number for
% constants in the generated C code.
:- pred module_info_get_cell_count(module_info, int).
:- mode module_info_get_cell_count(in, out) is det.
Index: compiler/ite_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ite_gen.m,v
retrieving revision 1.55
diff -u -r1.55 ite_gen.m
--- ite_gen.m 1998/06/02 05:31:39 1.55
+++ ite_gen.m 1998/07/01 12:16:39
@@ -3,19 +3,16 @@
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
-%---------------------------------------------------------------------------%
%
% File: ite_gen.m
%
% Main authors: conway, fjh, zs.
%
-% The predicates of this module generate code for if-then-elses.
-%
-% The handling of model_det and model_semi if-then-elses is almost identical.
-% The handling of model_non if-then-elses is also quite similar.
+% The predicates of this module generate code for if-then-elses, and for
+% negations (which are cut-down versions of if-then-elses, since not(G)
+% is equivalent to (G -> fail ; true).
%
%---------------------------------------------------------------------------%
-%---------------------------------------------------------------------------%
:- module ite_gen.
@@ -23,63 +20,58 @@
:- import_module hlds_goal, llds, code_info.
-:- pred ite_gen__generate_det_ite(hlds_goal, hlds_goal, hlds_goal,
- store_map, code_tree, code_info, code_info).
-:- mode ite_gen__generate_det_ite(in, in, in, in, out, in, out) is det.
-
-:- pred ite_gen__generate_semidet_ite(hlds_goal, hlds_goal, hlds_goal,
- store_map, code_tree, code_info, code_info).
-:- mode ite_gen__generate_semidet_ite(in, in, in, in, out, in, out) is det.
-
-:- pred ite_gen__generate_nondet_ite(hlds_goal, hlds_goal, hlds_goal,
- store_map, code_tree, code_info, code_info).
-:- mode ite_gen__generate_nondet_ite(in, in, in, in, out, in, out) is det.
+:- pred ite_gen__generate_ite(code_model::in, hlds_goal::in, hlds_goal::in,
+ hlds_goal::in, store_map::in, code_tree::out,
+ code_info::in, code_info::out) is det.
+
+:- pred ite_gen__generate_negation(code_model::in, hlds_goal::in,
+ code_tree::out, code_info::in, code_info::out) is det.
%---------------------------------------------------------------------------%
:- implementation.
:- import_module code_gen, code_util, trace, options, globals.
-:- import_module bool, set, tree, list, map, std_util, require.
-
-ite_gen__generate_det_ite(CondGoal, ThenGoal, ElseGoal, StoreMap, Code) -->
- ite_gen__generate_basic_ite(CondGoal, ThenGoal, ElseGoal, StoreMap,
- model_det, Code).
-
-ite_gen__generate_semidet_ite(CondGoal, ThenGoal, ElseGoal, StoreMap, Code) -->
- ite_gen__generate_basic_ite(CondGoal, ThenGoal, ElseGoal, StoreMap,
- model_semi, Code).
-
-%---------------------------------------------------------------------------%
+:- import_module bool, set, tree, list, map, std_util, term, require.
-:- pred ite_gen__generate_basic_ite(hlds_goal, hlds_goal, hlds_goal,
- store_map, code_model, code_tree, code_info, code_info).
-:- mode ite_gen__generate_basic_ite(in, in, in, in, in, out, in, out) is det.
-
-ite_gen__generate_basic_ite(CondGoal0, ThenGoal, ElseGoal, StoreMap, CodeModel,
- Code) -->
-
- % Set up for the possible failure of the condition
+ite_gen__generate_ite(CodeModel, CondGoal0, ThenGoal, ElseGoal, StoreMap, Code)
+ -->
{ CondGoal0 = CondExpr - CondInfo0 },
+ { goal_info_get_code_model(CondInfo0, CondCodeModel) },
+ {
+ CodeModel = model_non,
+ CondCodeModel \= model_non
+ ->
+ EffCodeModel = model_semi
+ ;
+ EffCodeModel = CodeModel
+ },
+
{ goal_info_get_resume_point(CondInfo0, Resume) },
- (
- { Resume = resume_point(ResumeVarsPrime, ResumeLocsPrime) }
+ {
+ Resume = resume_point(ResumeVarsPrime, ResumeLocsPrime)
->
- { ResumeVars = ResumeVarsPrime },
- { ResumeLocs = ResumeLocsPrime }
+ ResumeVars = ResumeVarsPrime,
+ ResumeLocs = ResumeLocsPrime,
+ % The pre_goal_update sanity check insists on
+ % no_resume_point, to make sure that all resume
+ % points have been handled by surrounding code.
+ goal_info_set_resume_point(CondInfo0, no_resume_point,
+ CondInfo),
+ CondGoal = CondExpr - CondInfo
;
- { error("condition of an if-then-else has no resume point") }
- ),
- code_info__make_known_failure_cont(ResumeVars, ResumeLocs, no,
- ModContCode),
- % The next line is to enable Cond to pass the
- % pre_goal_update sanity check
- { goal_info_set_resume_point(CondInfo0, no_resume_point, CondInfo) },
- { CondGoal = CondExpr - CondInfo },
+ error("condition of an if-then-else has no resume point")
+ },
- % 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
+ % Make sure that the variables whose values will be needed
+ % on backtracking to the else part are materialized into
+ % registers or stack slots. Their locations are recorded
+ % in ResumeMap.
+ code_info__produce_vars(ResumeVars, ResumeMap, FlushCode),
+
+ % Maybe save the heap state current before the condition.
+ % This is after code_info__produce_vars since code that
+ % flushes the cache may allocate memory we must not "recover".
code_info__get_globals(Globals),
{
globals__lookup_bool_option(Globals,
@@ -90,225 +82,338 @@
;
ReclaimHeap = no
},
- code_info__maybe_save_hp(ReclaimHeap, SaveHPCode, MaybeHpSlot),
+ code_info__maybe_save_hp(ReclaimHeap, SaveHpCode, MaybeHpSlot),
% Maybe save the current trail state before the condition
{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
- code_info__maybe_save_ticket(UseTrail, SaveTicketCode, MaybeTicketSlot),
+ code_info__maybe_save_ticket(UseTrail, SaveTicketCode,
+ MaybeTicketSlot),
- code_info__grab_code_info(CodeInfo),
+ code_info__remember_position(BranchStart),
- % Generate the condition as a semi-deterministic goal
- code_info__push_resume_point_vars(ResumeVars),
- code_gen__generate_goal(model_semi, CondGoal, CondCode),
- code_info__pop_resume_point_vars,
+ code_info__prepare_for_ite_hijack(EffCodeModel, HijackInfo,
+ PrepareHijackCode),
+
+ code_info__make_resume_point(ResumeVars, ResumeLocs, ResumeMap,
+ ResumePoint),
+ code_info__effect_resume_point(ResumePoint, EffCodeModel,
+ EffectResumeCode),
+
+ { goal_may_hijack_top_redoip(CondGoal, CondMayHijack) },
+ code_info__maybe_push_temp_frame(EffCodeModel, CondMayHijack,
+ HijackInfo, CurFrameLval, TempFrameCode),
+
+ % Generate the condition
+ code_gen__generate_goal(CondCodeModel, CondGoal, CondCode),
+
+ code_info__ite_enter_then(HijackInfo, CurFrameLval,
+ ThenNeckCode, ElseNeckCode),
% Kill again any variables that have become zombies
code_info__pickup_zombies(Zombies),
code_info__make_vars_forward_dead(Zombies),
- code_info__pop_failure_cont,
-
% Discard hp and trail ticket if the condition succeeded
+ % XXX is this the right thing to do?
code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot, commit,
DiscardTicketCode),
code_info__maybe_discard_hp(MaybeHpSlot),
+ % XXX release any temp slots holding heap or trail pointers
+
+ % XXX If instmap indicates we cannot reach then part,
+ % do not attempt to generate it (may cause aborts)
+
% Generate the then branch
trace__maybe_generate_internal_event_code(ThenGoal, ThenTraceCode),
code_gen__generate_goal(CodeModel, ThenGoal, ThenCode),
- code_info__generate_branch_end(CodeModel, StoreMap, ThenSaveCode),
+ code_info__generate_branch_end(StoreMap, no, MaybeEnd0, ThenSaveCode),
% Generate the entry to the else branch
- 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_info__reset_to_position(BranchStart),
+ code_info__generate_resume_point(ResumePoint, ResumeCode),
+
+ ( { CondCodeModel = model_non } ->
+ % We cannot release the stack slots used for
+ % the trail ticket and heap pointer if the
+ % condition can be backtracked into.
+ code_info__maybe_restore_hp(MaybeHpSlot, RestoreHpCode),
+ code_info__maybe_reset_and_pop_ticket(MaybeTicketSlot,
+ undo, RestoreTicketCode)
+ ;
+ code_info__maybe_restore_and_discard_hp(MaybeHpSlot,
+ RestoreHpCode),
+ code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot,
+ undo, RestoreTicketCode)
+ ),
% Generate the else branch
trace__maybe_generate_internal_event_code(ElseGoal, ElseTraceCode),
code_gen__generate_goal(CodeModel, ElseGoal, ElseCode),
- code_info__generate_branch_end(CodeModel, StoreMap, ElseSaveCode),
+ code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd,
+ ElseSaveCode),
- code_info__get_next_label(EndLab),
- { JumpToEndCode = node([goto(label(EndLab))
- - "Jump to the end of if-then-else"]) },
- { EndLabelCode = node([label(EndLab) - "end of if-then-else"]) },
- { Code = tree(ModContCode,
- tree(SaveHPCode,
- tree(SaveTicketCode,
- tree(CondCode,
- tree(DiscardTicketCode,
- tree(ThenTraceCode,
- tree(ThenCode,
- tree(ThenSaveCode,
- tree(JumpToEndCode,
- tree(RestoreContCode,
- tree(RestoreHPCode,
- tree(RestoreTicketCode,
- tree(ElseTraceCode,
- tree(ElseCode,
- tree(ElseSaveCode,
- EndLabelCode)))))))))))))))
+ code_info__get_next_label(EndLabel),
+ { JumpToEndCode = node([
+ goto(label(EndLabel))
+ - "Jump to the end of if-then-else"
+ ]) },
+ { EndLabelCode = node([
+ label(EndLabel)
+ - "end of if-then-else"
+ ]) },
+ { Code =
+ tree(FlushCode,
+ tree(SaveHpCode,
+ tree(SaveTicketCode,
+ tree(PrepareHijackCode,
+ tree(EffectResumeCode,
+ tree(TempFrameCode,
+ tree(CondCode,
+ tree(ThenNeckCode,
+ tree(DiscardTicketCode,
+ tree(ThenTraceCode,
+ tree(ThenCode,
+ tree(ThenSaveCode,
+ tree(JumpToEndCode,
+ tree(ResumeCode,
+ tree(ElseNeckCode,
+ tree(RestoreHpCode,
+ tree(RestoreTicketCode,
+ tree(ElseTraceCode,
+ tree(ElseCode,
+ tree(ElseSaveCode,
+ EndLabelCode))))))))))))))))))))
},
- code_info__remake_with_store_map(StoreMap).
+ code_info__after_all_branches(StoreMap, MaybeEnd).
%---------------------------------------------------------------------------%
-ite_gen__generate_nondet_ite(CondGoal0, ThenGoal, ElseGoal, StoreMap, Code) -->
+ite_gen__generate_negation(CodeModel, Goal0, Code) -->
+ { CodeModel = model_non ->
+ error("nondet negation")
+ ;
+ true
+ },
- % Set up for the possible failure of the condition
- { CondGoal0 = CondExpr - CondInfo0 },
- { goal_info_get_code_model(CondInfo0, CondCodeModel) },
- ( { CondCodeModel = model_non } ->
- { NondetCond = yes }
+ { Goal0 = GoalExpr - GoalInfo0 },
+ { goal_info_get_resume_point(GoalInfo0, Resume) },
+ {
+ Resume = resume_point(ResumeVarsPrime, ResumeLocsPrime)
+ ->
+ ResumeVars = ResumeVarsPrime,
+ ResumeLocs = ResumeLocsPrime,
+ goal_info_set_resume_point(GoalInfo0, no_resume_point,
+ GoalInfo),
+ Goal = GoalExpr - GoalInfo
;
- { NondetCond = no }
- ),
- { goal_info_get_resume_point(CondInfo0, Resume) },
+ error("negated goal has no resume point")
+ },
+
+ % For a negated simple test, we can generate better code
+ % than the general mechanism, because we don't have to
+ % flush the cache.
(
- { Resume = resume_point(ResumeVarsPrime, ResumeLocsPrime) }
+ { 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) }
->
- { ResumeVars = ResumeVarsPrime},
- { ResumeLocs = ResumeLocsPrime}
+ % Because we are generating the negated goal ourselves,
+ % we need to apply the pre- and post-goal updates
+ % that would normally be applied by
+ % code_gen__generate_goal.
+
+ code_info__enter_simple_neg(ResumeVars, GoalInfo, SimpleNeg),
+ 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__leave_simple_neg(GoalInfo, SimpleNeg),
+ { Code = tree(tree(CodeL, CodeR), TestCode) }
;
- { error("condition of an if-then-else has no resume point") }
- ),
- code_info__make_known_failure_cont(ResumeVars, ResumeLocs, NondetCond,
- ModContCode),
- % The next line is to enable Cond to pass the
- % pre_goal_update sanity check
- { goal_info_set_resume_point(CondInfo0, no_resume_point, CondInfo) },
- { CondGoal = CondExpr - CondInfo },
-
- % Prevent a nondet condition from hijacking the redoip slot
- % We could improve the efficiency of this
- ( { NondetCond = yes } ->
- code_info__unset_failure_cont(FlushEnclosingResumeVarsCode),
- code_info__save_maxfr(MaxfrLval0, SaveMaxfrCode),
- { MaybeMaxfrLval = yes(MaxfrLval0) }
- ;
- { FlushEnclosingResumeVarsCode = empty },
- { SaveMaxfrCode = empty },
- { MaybeMaxfrLval = no }
- ),
+ generate_negation_general(CodeModel, Goal,
+ ResumeVars, ResumeLocs, Code)
+ ).
+
+ % The code of generate_negation_general is a cut-down version
+ % of the code for if-then-elses.
+
+:- pred generate_negation_general(code_model::in, hlds_goal::in,
+ set(var)::in, resume_locs::in, code_tree::out,
+ code_info::in, code_info::out) is det.
+
+generate_negation_general(CodeModel, Goal, ResumeVars, ResumeLocs, Code) -->
+
+ code_info__produce_vars(ResumeVars, ResumeMap, FlushCode),
% 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(CondGoal)
+ code_util__goal_may_allocate_heap(Goal)
->
ReclaimHeap = yes
;
ReclaimHeap = no
},
- code_info__maybe_save_hp(ReclaimHeap, SaveHPCode, MaybeHpSlot),
+ code_info__maybe_save_hp(ReclaimHeap, SaveHpCode, MaybeHpSlot),
- % Maybe save the current trail state before the condition
{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
- code_info__maybe_save_ticket(UseTrail, SaveTicketCode, MaybeTicketSlot),
+ code_info__maybe_save_ticket(UseTrail, SaveTicketCode,
+ MaybeTicketSlot),
- code_info__grab_code_info(CodeInfo),
+ code_info__prepare_for_ite_hijack(CodeModel, HijackInfo,
+ PrepareHijackCode),
- % Generate the condition as either a semi-deterministic
- % or as a non-deterministic goal (the failure continuation
- % must be set up the same way)
- code_info__push_resume_point_vars(ResumeVars),
- code_gen__generate_goal(CondCodeModel, CondGoal, CondCode),
- code_info__pop_resume_point_vars,
+ code_info__make_resume_point(ResumeVars, ResumeLocs, ResumeMap,
+ ResumePoint),
+ code_info__effect_resume_point(ResumePoint, CodeModel,
+ EffectResumeCode),
+
+ { goal_may_hijack_top_redoip(Goal, MayHijack) },
+ code_info__maybe_push_temp_frame(CodeModel, MayHijack,
+ HijackInfo, CurFrameLval, TempFrameCode),
- code_info__pop_failure_cont,
- ( { MaybeMaxfrLval = yes(MaxfrLval) } ->
- code_info__do_soft_cut(MaxfrLval, SoftCutCode, SoftCutContCode),
- code_info__unset_failure_cont(FlushCode)
- % XXX why call unset_failure_cont here?
- % We're going to call it from branch_end at the
- % end of the `then' anyway, so is this
- % one really necessary?
- ;
- { SoftCutCode = empty },
- { SoftCutContCode = empty },
- { FlushCode = empty }
- ),
+ % Generate the negated goal.
+ code_gen__generate_goal(CodeModel, Goal, GoalCode),
+
+ code_info__ite_enter_then(HijackInfo, CurFrameLval,
+ ThenNeckCode, ElseNeckCode),
% Kill again any variables that have become zombies
code_info__pickup_zombies(Zombies),
code_info__make_vars_forward_dead(Zombies),
- % Discard hp and maybe trail ticket if the condition succeeded
- code_info__maybe_discard_hp(MaybeHpSlot),
- ( { NondetCond = yes } ->
- % We cannot discard the trail ticket if the
- % condition can be backtracked into.
- % But we do need to call reset_ticket(..., solve)
- % to check for floundering.
- code_info__maybe_reset_ticket(MaybeTicketSlot,
- solve, DiscardTicketCode)
+ code_info__get_forward_live_vars(LiveVars),
+
+ ( { CodeModel = model_det } ->
+ % the then branch will never be reached
+ { DiscardTicketCode = empty },
+ { FailCode = empty }
;
- % Discard the trail ticket if the condition succeeded
- % and we will not backtrack into the condition
+ code_info__remember_position(AfterNegatedGoal),
+ % 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)
+ commit, DiscardTicketCode),
+ code_info__generate_failure(FailCode),
+ % We want liveness after not(G) to be the same as
+ % after G. Information about what variables are where
+ % will be set by code_info__generate_resume_point.
+ code_info__reset_to_position(AfterNegatedGoal)
),
- % Generate the then branch
- trace__maybe_generate_internal_event_code(ThenGoal, ThenTraceCode),
- code_gen__generate_goal(model_non, ThenGoal, ThenCode),
- code_info__generate_branch_end(model_non, StoreMap, ThenSaveCode),
-
% Generate the entry to the else branch
- code_info__slap_code_info(CodeInfo),
- code_info__restore_failure_cont(RestoreContCode),
- ( { NondetCond = yes } ->
- % We cannot release the stack slots used for
- % the trail ticket and heap pointer if the
- % condition can be backtracked into.
- code_info__maybe_restore_hp(MaybeHpSlot, RestoreHPCode),
- code_info__maybe_reset_and_pop_ticket(MaybeTicketSlot,
- undo, RestoreTicketCode)
+ code_info__generate_resume_point(ResumePoint, ResumeCode),
+
+ code_info__set_forward_live_vars(LiveVars),
+
+ code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot, undo,
+ RestoreTicketCode),
+ code_info__maybe_restore_and_discard_hp(MaybeHpSlot, RestoreHpCode),
+
+ { Code =
+ tree(FlushCode,
+ tree(PrepareHijackCode,
+ tree(EffectResumeCode,
+ tree(TempFrameCode,
+ tree(SaveHpCode,
+ tree(SaveTicketCode,
+ tree(GoalCode,
+ tree(ThenNeckCode,
+ tree(DiscardTicketCode,
+ tree(FailCode,
+ tree(ResumeCode,
+ tree(ElseNeckCode,
+ tree(RestoreTicketCode,
+ RestoreHpCode)))))))))))))
+ }.
+
+%---------------------------------------------------------------------------%
+
+:- pred goal_may_hijack_top_redoip(hlds_goal::in, bool::out) is det.
+
+goal_may_hijack_top_redoip(GoalExpr - GoalInfo, MayHijack) :-
+ (
+ GoalExpr = conj(Conj),
+ goals_may_hijack_top_redoip(Conj, MayHijack)
;
- code_info__maybe_restore_and_discard_hp(MaybeHpSlot,
- RestoreHPCode),
- code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot,
- undo, RestoreTicketCode)
- ),
+ GoalExpr = par_conj(Conj, _),
+ goals_may_hijack_top_redoip(Conj, MayHijack)
+ ;
+ GoalExpr = call(_, _, _, _, _, _),
+ MayHijack = yes
+ ;
+ GoalExpr = higher_order_call(_, _, _, _, _, _),
+ MayHijack = yes
+ ;
+ GoalExpr = class_method_call(_, _, _, _, _, _),
+ MayHijack = yes
+ ;
+ GoalExpr = switch(_, _, Cases, _),
+ cases_may_hijack_top_redoip(Cases, MayHijack)
+ ;
+ GoalExpr = unify(_, _, _, _, _),
+ MayHijack = no
+ ;
+ GoalExpr = disj(Disj, _),
+ (
+ goal_info_get_code_model(GoalInfo, CodeModel),
+ CodeModel = model_non
+ ->
+ MayHijack = yes
+ ;
+ goals_may_hijack_top_redoip(Disj, MayHijack)
+ )
+ ;
+ GoalExpr = not(_SubGoal),
+ MayHijack = yes
+ ;
+ GoalExpr = some(_, _SubGoal),
+ MayHijack = yes
+ ;
+ GoalExpr = if_then_else(_, _, _, _, _),
+ MayHijack = yes
+ ;
+ GoalExpr = pragma_c_code(_, _, _, _, _, _, _),
+ MayHijack = yes
+ ).
+
+:- pred goals_may_hijack_top_redoip(list(hlds_goal)::in, bool::out) is det.
+
+goals_may_hijack_top_redoip([], no).
+goals_may_hijack_top_redoip([Goal | Goals], MayHijack) :-
+ goal_may_hijack_top_redoip(Goal, MayHijack0),
+ ( MayHijack0 = yes ->
+ MayHijack = yes
+ ;
+ goals_may_hijack_top_redoip(Goals, MayHijack)
+ ).
- % Generate the else branch
- trace__maybe_generate_internal_event_code(ElseGoal, ElseTraceCode),
- code_gen__generate_goal(model_non, ElseGoal, ElseCode),
- code_info__generate_branch_end(model_non, StoreMap, ElseSaveCode),
+:- pred cases_may_hijack_top_redoip(list(case)::in, bool::out) is det.
- code_info__get_next_label(EndLab),
- { JumpToEndCode = node([goto(label(EndLab))
- - "Jump to the end of if-then-else"]) },
- { EndLabelCode = node([label(EndLab) - "end of if-then-else"]) },
- { Code = tree(ModContCode,
- tree(FlushEnclosingResumeVarsCode,
- tree(SaveMaxfrCode,
- tree(SaveHPCode,
- tree(SaveTicketCode,
- tree(CondCode,
- tree(SoftCutCode,
- tree(FlushCode,
- tree(DiscardTicketCode,
- tree(ThenTraceCode,
- tree(ThenCode,
- tree(ThenSaveCode,
- tree(JumpToEndCode,
- tree(SoftCutContCode,
- tree(RestoreContCode,
- tree(RestoreHPCode,
- tree(RestoreTicketCode,
- tree(ElseTraceCode,
- tree(ElseCode,
- tree(ElseSaveCode,
- EndLabelCode))))))))))))))))))))
- },
- code_info__remake_with_store_map(StoreMap).
+cases_may_hijack_top_redoip([], no).
+cases_may_hijack_top_redoip([case(_, Goal) | Goals], MayHijack) :-
+ goal_may_hijack_top_redoip(Goal, MayHijack0),
+ ( MayHijack0 = yes ->
+ MayHijack = yes
+ ;
+ cases_may_hijack_top_redoip(Goals, MayHijack)
+ ).
%---------------------------------------------------------------------------%
Index: compiler/jumpopt.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/jumpopt.m,v
retrieving revision 1.43
diff -u -r1.43 jumpopt.m
--- jumpopt.m 1998/01/23 12:56:39 1.43
+++ jumpopt.m 1998/02/27 02:24:17
@@ -66,8 +66,13 @@
map__init(Forkmap0),
jumpopt__build_forkmap(Instrs0, Sdprocmap, Forkmap0, Forkmap),
jumpopt__instr_list(Instrs0, comment(""), Instrmap, Blockmap, Lvalmap,
- Procmap, Sdprocmap, Forkmap, Succmap, Instrs1, Mod),
- opt_util__filter_out_bad_livevals(Instrs1, Instrs).
+ Procmap, Sdprocmap, Forkmap, Succmap, Instrs1),
+ opt_util__filter_out_bad_livevals(Instrs1, Instrs),
+ ( Instrs = Instrs0 ->
+ Mod = no
+ ;
+ Mod = yes
+ ).
%-----------------------------------------------------------------------------%
@@ -179,14 +184,14 @@
% between the if-val and the goto.
:- pred jumpopt__instr_list(list(instruction), instr, instrmap, tailmap,
- lvalmap, tailmap, tailmap, tailmap, tailmap, list(instruction), bool).
-:- mode jumpopt__instr_list(in, in, in, in, in, in, in, in, in, out, out)
+ lvalmap, tailmap, tailmap, tailmap, tailmap, list(instruction)).
+:- mode jumpopt__instr_list(in, in, in, in, in, in, in, in, in, out)
is det.
jumpopt__instr_list([], _PrevInstr, _Instrmap, _Blockmap,
- _Lvalmap, _Procmap, _Sdprocmap, _Forkmap, _Succmap, [], no).
+ _Lvalmap, _Procmap, _Sdprocmap, _Forkmap, _Succmap, []).
jumpopt__instr_list([Instr0 | Instrs0], PrevInstr, Instrmap, Blockmap,
- Lvalmap, Procmap, Sdprocmap, Forkmap, Succmap, Instrs, Mod) :-
+ Lvalmap, Procmap, Sdprocmap, Forkmap, Succmap, Instrs) :-
Instr0 = Uinstr0 - Comment0,
string__append(Comment0, " (redirected return)", Redirect),
(
@@ -204,8 +209,7 @@
opt_util__filter_out_livevals(Between0, Between1),
list__append(Between1, [livevals(Livevals) - "",
goto(Proc) - Redirect], NewInstrs),
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
% Look for semidet style tailcalls.
CallModel = semidet,
@@ -214,8 +218,7 @@
->
list__append(Between, [livevals(Livevals) - "",
goto(Proc) - Redirect], NewInstrs),
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
% Look for nondet style tailcalls.
CallModel = nondet(yes),
@@ -233,8 +236,7 @@
livevals(Livevals) - "",
goto(Proc) - Redirect
],
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
% Short circuit the return label if possible.
map__search(Instrmap, RetLabel, RetInstr)
@@ -243,18 +245,15 @@
DestLabel, _DestInstr),
( RetLabel = DestLabel ->
NewInstrs = [Instr0],
- RemainInstrs = Instrs0,
- Mod0 = no
+ RemainInstrs = Instrs0
;
NewInstrs = [call(Proc, label(DestLabel),
GC, CallModel) - Redirect],
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
)
;
NewInstrs = [Instr0],
- RemainInstrs = Instrs0,
- Mod0 = no
+ RemainInstrs = Instrs0
)
;
Uinstr0 = goto(label(TargetLabel))
@@ -264,8 +263,7 @@
opt_util__is_this_label_next(TargetLabel, Instrs0, _)
->
NewInstrs = [],
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
PrevInstr = if_val(_, label(IfTargetLabel)),
opt_util__is_this_label_next(IfTargetLabel, Instrs0, _)
@@ -277,8 +275,7 @@
% We cannot eliminate the instruction here because
% that would require altering the if_val instruction.
NewInstrs = [Instr0],
- RemainInstrs = Instrs0,
- Mod0 = no
+ RemainInstrs = Instrs0
;
% Replace a jump to a det epilog with the epilog.
map__search(Procmap, TargetLabel, Between0)
@@ -286,8 +283,7 @@
jumpopt__adjust_livevals(PrevInstr, Between0, Between),
list__append(Between, [goto(succip) - "shortcircuit"],
NewInstrs),
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
% Replace a jump to a semidet epilog with the epilog.
map__search(Sdprocmap, TargetLabel, Between0)
@@ -295,16 +291,14 @@
jumpopt__adjust_livevals(PrevInstr, Between0, Between),
list__append(Between, [goto(succip) - "shortcircuit"],
NewInstrs),
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
% Replace a jump to a nondet epilog with the epilog.
map__search(Succmap, TargetLabel, BetweenIncl0)
->
jumpopt__adjust_livevals(PrevInstr, BetweenIncl0,
NewInstrs),
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
% Replace a jump to a non-epilog block with the
% block itself. These jumps are treated separately
@@ -336,9 +330,8 @@
map__delete(Blockmap, DestLabel, CrippledBlockmap),
jumpopt__instr_list(AdjustedBlock, comment(""),
Instrmap, CrippledBlockmap, Lvalmap, Procmap,
- Sdprocmap, Forkmap, Succmap, NewInstrs, _),
- RemainInstrs = Instrs0,
- Mod0 = yes
+ Sdprocmap, Forkmap, Succmap, NewInstrs),
+ RemainInstrs = Instrs0
;
% Short-circuit the goto.
map__search(Instrmap, TargetLabel, TargetInstr)
@@ -352,18 +345,15 @@
Canfallthrough),
( Canfallthrough = no ->
NewInstrs0 = [UdestInstr - Shorted],
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
( TargetLabel = DestLabel ->
NewInstrs0 = [Instr0],
- RemainInstrs = Instrs0,
- Mod0 = no
+ RemainInstrs = Instrs0
;
NewInstrs0 = [goto(label(DestLabel))
- Shorted],
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
)
),
( map__search(Lvalmap, DestLabel, yes(Lvalinstr)) ->
@@ -374,19 +364,18 @@
)
;
NewInstrs = [Instr0],
- RemainInstrs = Instrs0,
- Mod0 = no
+ RemainInstrs = Instrs0
)
; Uinstr0 = computed_goto(Index, LabelList0) ->
% Short-circuit all the destination labels.
- jumpopt__short_labels(LabelList0, Instrmap, LabelList, Mod0),
+ jumpopt__short_labels(LabelList0, Instrmap, LabelList),
RemainInstrs = Instrs0,
- ( Mod0 = yes ->
+ ( LabelList = LabelList0 ->
+ NewInstrs = [Instr0]
+ ;
string__append(Comment0, " (some shortcircuits)",
Shorted),
NewInstrs = [computed_goto(Index, LabelList) - Shorted]
- ;
- NewInstrs = [Instr0]
)
; Uinstr0 = if_val(Cond, label(TargetLabel)) ->
(
@@ -435,8 +424,7 @@
% the recursive call. We can't go into an infinite
% loop because each application of the transformation
% strictly reduces the size of the code.
- RemainInstrs = [NewInstr | AfterGoto],
- Mod0 = yes
+ RemainInstrs = [NewInstr | AfterGoto]
;
map__search(Instrmap, TargetLabel, TargetInstr)
->
@@ -486,8 +474,7 @@
Proceed = goto(succip) - "shortcircuit",
list__append([NewAssign | Between], [Proceed],
NewInstrs),
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
% Try to short-circuit the destination.
@@ -497,22 +484,29 @@
Comment0, Shorted),
NewInstrs = [if_val(Cond, label(DestLabel))
- Shorted],
- RemainInstrs = Instrs0,
- Mod0 = yes
+ RemainInstrs = Instrs0
;
NewInstrs = [Instr0],
- RemainInstrs = Instrs0,
- Mod0 = no
+ RemainInstrs = Instrs0
)
;
NewInstrs = [Instr0],
- RemainInstrs = Instrs0,
- Mod0 = no
+ RemainInstrs = Instrs0
+ )
+ ; Uinstr0 = assign(Lval, Rval0) ->
+ % Any labels mentioned in Rval0 should be short-circuited.
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval),
+ RemainInstrs = Instrs0,
+ ( Rval = Rval0 ->
+ NewInstrs = [Instr0]
+ ;
+ string__append(Comment0, " (some shortcircuits)",
+ Shorted),
+ NewInstrs = [assign(Lval, Rval) - Shorted]
)
;
NewInstrs = [Instr0],
- RemainInstrs = Instrs0,
- Mod0 = no
+ RemainInstrs = Instrs0
),
( ( Uinstr0 = comment(_) ; NewInstrs = [] ) ->
NewPrevInstr = PrevInstr
@@ -520,13 +514,8 @@
NewPrevInstr = Uinstr0
),
jumpopt__instr_list(RemainInstrs, NewPrevInstr, Instrmap, Blockmap,
- Lvalmap, Procmap, Sdprocmap, Forkmap, Succmap, Instrs9, Mod1),
- list__append(NewInstrs, Instrs9, Instrs),
- ( Mod0 = no, Mod1 = no ->
- Mod = no
- ;
- Mod = yes
- ).
+ Lvalmap, Procmap, Sdprocmap, Forkmap, Succmap, Instrs9),
+ list__append(NewInstrs, Instrs9, Instrs).
% We avoid generating statements that redefine the value of a location
% by comparing its old contents for non-equality with zero.
@@ -588,32 +577,25 @@
% Short-circuit the given label by following any gotos at the
% labelled instruction or by falling through consecutive labels.
-:- pred jumpopt__short_label(label, instrmap, label, bool).
-:- mode jumpopt__short_label(in, in, out, out) is det.
+:- pred jumpopt__short_label(label, instrmap, label).
+:- mode jumpopt__short_label(in, in, out) is det.
-jumpopt__short_label(Label0, Instrmap, Label, Mod) :-
- map__lookup(Instrmap, Label0, Instr0),
- jumpopt__final_dest(Label0, Instr0, Instrmap, Label, _Instr),
- ( Label = Label0 ->
- Mod = no
+jumpopt__short_label(Label0, Instrmap, Label) :-
+ ( map__search(Instrmap, Label0, Instr0) ->
+ jumpopt__final_dest(Label0, Instr0, Instrmap, Label, _Instr)
;
- Mod = yes
+ Label = Label0
).
-:- pred jumpopt__short_labels(list(label), instrmap, list(label), bool).
-:- mode jumpopt__short_labels(in, in, out, out) is det.
+:- pred jumpopt__short_labels(list(label), instrmap, list(label)).
+:- mode jumpopt__short_labels(in, in, out) is det.
% XXX these uses of the Mod argument should be replaced by accumulator passing
-jumpopt__short_labels([], _Instrmap, [], no).
-jumpopt__short_labels([Label0 | Labels0], Instrmap, [Label | Labels], Mod) :-
- jumpopt__short_label(Label0, Instrmap, Label, Mod1),
- jumpopt__short_labels(Labels0, Instrmap, Labels, Mod2),
- ( Mod1 = no, Mod2 = no ->
- Mod = no
- ;
- Mod = yes
- ).
+jumpopt__short_labels([], _Instrmap, []).
+jumpopt__short_labels([Label0 | Labels0], Instrmap, [Label | Labels]) :-
+ jumpopt__short_label(Label0, Instrmap, Label),
+ jumpopt__short_labels(Labels0, Instrmap, Labels).
%-----------------------------------------------------------------------------%
@@ -649,5 +631,99 @@
DestLabel = SrcLabel,
DestInstr = SrcInstr
).
+
+%-----------------------------------------------------------------------------%
+
+:- pred jumpopt__short_labels_rval(rval, instrmap, rval).
+:- mode jumpopt__short_labels_rval(in, in, out) is det.
+
+jumpopt__short_labels_rval(lval(Lval0), Instrmap, lval(Lval)) :-
+ jumpopt__short_labels_lval(Lval0, Instrmap, Lval).
+jumpopt__short_labels_rval(var(_), _, _) :-
+ error("var rval in jumpopt__short_labels_rval").
+jumpopt__short_labels_rval(create(Tag, Rvals0, Unique, Cell, Type), Instrmap,
+ create(Tag, Rvals, Unique, Cell, Type)) :-
+ jumpopt__short_labels_maybe_rvals(Rvals0, Instrmap, Rvals).
+jumpopt__short_labels_rval(mkword(Tag, Rval0), Instrmap,
+ mkword(Tag, Rval)) :-
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_rval(const(Const0), Instrmap, const(Const)) :-
+ jumpopt__short_labels_const(Const0, Instrmap, Const).
+jumpopt__short_labels_rval(unop(Op, Rval0), Instrmap, unop(Op, Rval)) :-
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_rval(binop(Op, LRval0, RRval0), Instrmap,
+ binop(Op, LRval, RRval)) :-
+ jumpopt__short_labels_rval(LRval0, Instrmap, LRval),
+ jumpopt__short_labels_rval(RRval0, Instrmap, RRval).
+jumpopt__short_labels_rval(mem_addr(MemRef), _, mem_addr(MemRef)).
+
+:- pred jumpopt__short_labels_const(rval_const, instrmap, rval_const).
+:- mode jumpopt__short_labels_const(in, in, out) is det.
+
+jumpopt__short_labels_const(true, _, true).
+jumpopt__short_labels_const(false, _, false).
+jumpopt__short_labels_const(int_const(I), _, int_const(I)).
+jumpopt__short_labels_const(float_const(F), _, float_const(F)).
+jumpopt__short_labels_const(string_const(S), _, string_const(S)).
+jumpopt__short_labels_const(label_entry(Label0), Instrmap,
+ label_entry(Label)) :-
+ jumpopt__short_label(Label0, Instrmap, Label).
+jumpopt__short_labels_const(code_addr_const(CodeAddr0), Instrmap,
+ code_addr_const(CodeAddr)) :-
+ ( CodeAddr0 = label(Label0) ->
+ jumpopt__short_label(Label0, Instrmap, Label),
+ CodeAddr = label(Label)
+ ;
+ CodeAddr = CodeAddr0
+ ).
+jumpopt__short_labels_const(data_addr_const(D), _, data_addr_const(D)).
+
+:- pred jumpopt__short_labels_maybe_rvals(list(maybe(rval)), instrmap,
+ list(maybe(rval))).
+:- mode jumpopt__short_labels_maybe_rvals(in, in, out) is det.
+
+jumpopt__short_labels_maybe_rvals([], _, []).
+jumpopt__short_labels_maybe_rvals([MaybeRval0 | MaybeRvals0], Instrmap,
+ [MaybeRval | MaybeRvals]) :-
+ (
+ MaybeRval0 = no,
+ MaybeRval = no
+ ;
+ MaybeRval0 = yes(Rval0),
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval),
+ MaybeRval = yes(Rval)
+ ),
+ jumpopt__short_labels_maybe_rvals(MaybeRvals0, Instrmap, MaybeRvals).
+
+:- pred jumpopt__short_labels_lval(lval, instrmap, lval).
+:- mode jumpopt__short_labels_lval(in, in, out) is det.
+
+jumpopt__short_labels_lval(reg(T, N), _, reg(T, N)).
+jumpopt__short_labels_lval(succip, _, succip).
+jumpopt__short_labels_lval(maxfr, _, maxfr).
+jumpopt__short_labels_lval(curfr, _, curfr).
+jumpopt__short_labels_lval(hp, _, hp).
+jumpopt__short_labels_lval(sp, _, sp).
+jumpopt__short_labels_lval(temp(T, N), _, temp(T, N)).
+jumpopt__short_labels_lval(stackvar(N), _, stackvar(N)).
+jumpopt__short_labels_lval(framevar(N), _, framevar(N)).
+jumpopt__short_labels_lval(succip(Rval0), Instrmap, succip(Rval)) :-
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(redoip(Rval0), Instrmap, redoip(Rval)) :-
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(redofr(Rval0), Instrmap, redofr(Rval)) :-
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(succfr(Rval0), Instrmap, succfr(Rval)) :-
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(prevfr(Rval0), Instrmap, prevfr(Rval)) :-
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(field(Tag, Rval0, Field0), Instrmap,
+ field(Tag, Rval, Field)) :-
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval),
+ jumpopt__short_labels_rval(Field0, Instrmap, Field).
+jumpopt__short_labels_lval(mem_ref(Rval0), Instrmap, mem_ref(Rval)) :-
+ jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(lvar(_), _, _) :-
+ error("lvar lval in jumpopt__short_labels_lval").
%-----------------------------------------------------------------------------%
Index: compiler/livemap.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/livemap.m,v
retrieving revision 1.35
diff -u -r1.35 livemap.m
--- livemap.m 1998/06/09 02:13:13 1.35
+++ livemap.m 1998/06/29 08:00:26
@@ -160,7 +160,7 @@
Livemap = Livemap0,
DontValueNumber = DontValueNumber0
;
- Uinstr0 = mkframe(_, _, _, _),
+ Uinstr0 = mkframe(_, _),
Livemap = Livemap0,
Livevals = Livevals0,
Instrs = Instrs0,
Index: compiler/llds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds.m,v
retrieving revision 1.225
diff -u -r1.225 llds.m
--- llds.m 1998/06/09 02:13:21 1.225
+++ llds.m 1998/06/29 07:24:49
@@ -152,16 +152,16 @@
% says whether tail recursion elimination is
% potentially applicable to the call.
- ; mkframe(string, int, maybe(pragma_c_struct), code_addr)
- % mkframe(Comment, SlotCount, MaybePragmaStruct,
- % FailureContinuation) creates a nondet stack frame.
- % Comment says what predicate creates the frame.
- % SlotCount says how many ordinary framevar slots
- % it ought to have. If MaybePragmaStruct is yes,
- % the argument gives the details of the structure
- % which occupies the rest of the framevar slots.
- % CodeAddr is the code address to branch to when
- % trying to generate the next solution from this
+ ; mkframe(nondet_frame_info, code_addr)
+ % mkframe(NondetFrameInfo, CodeAddr) creates a nondet
+ % stack frame. NondetFrameInfo says whether the frame
+ % is an ordinary frame, containing the variables of a
+ % model_non procedure, or a temp frame used only for
+ % its redoip/redofr slots. If the former, it also
+ % gives the details of the size of the variable parts
+ % of the frame (temp frames have no variable sized
+ % parts). CodeAddr is the code address to branch to
+ % when trying to generate the next solution from this
% choice point.
; modframe(code_addr)
@@ -322,6 +322,17 @@
% term is specified by the given lval.
.
+:- type nondet_frame_info
+ ---> temp_frame
+ ; ordinary_frame(
+ string, % Name of the predicate.
+ int, % Number of framevar slots.
+ maybe(pragma_c_struct) % If yes, the frame should
+ % also contain this struct
+ % (for use by a model_non
+ % pragma C code).
+ ).
+
% Procedures defined by nondet pragma C codes must have some way of
% preserving information after a success, so that when control
% backtracks to the procedure, the C code knows what to do.
@@ -420,6 +431,7 @@
; curfr % a stored curfr
; maxfr % a stored maxfr
; redoip
+ ; redofr
; hp
; var(type, inst) % a variable
; unwanted. % something we don't need, or used as
@@ -485,6 +497,12 @@
% nondet stack frame; holds the code address
% to jump to on failure.
+ ; redofr(rval) % the redofr slot of the specified
+ % nondet stack frame; holds the address of
+ % the frame that the curfr register should be
+ % set to when backtracking through the redoip
+ % slot.
+
; succfr(rval) % The succfr slot of the specified
% nondet stack frame; holds the address of
% caller's nondet stack frame. On successful
@@ -774,6 +792,7 @@
llds__lval_type(framevar(_), word).
llds__lval_type(succip(_), code_ptr).
llds__lval_type(redoip(_), code_ptr).
+llds__lval_type(redofr(_), data_ptr).
llds__lval_type(succfr(_), data_ptr).
llds__lval_type(prevfr(_), data_ptr).
llds__lval_type(field(_, _, _), word).
Index: compiler/llds_common.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds_common.m,v
retrieving revision 1.18
diff -u -r1.18 llds_common.m
--- llds_common.m 1998/06/09 02:13:23 1.18
+++ llds_common.m 1998/06/29 08:00:32
@@ -180,7 +180,7 @@
Instr = Instr0,
Info = Info0
;
- Instr0 = mkframe(_, _, _, _),
+ Instr0 = mkframe(_, _),
Instr = Instr0,
Info = Info0
;
Index: compiler/llds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds_out.m,v
retrieving revision 1.84
diff -u -r1.84 llds_out.m
--- llds_out.m 1998/06/18 06:06:32 1.84
+++ llds_out.m 1998/07/01 12:43:19
@@ -215,6 +215,11 @@
:- mode output_c_file_mercury_headers(di, uo) is det.
output_c_file_mercury_headers -->
+ % The next two lines are only until MR_USE_REDOFR is default.
+ % The #undef avoids a warning if the invocation of mgnuc
+ % also supplies a definition on the command line.
+ io__write_string("#undef MR_USE_REDOFR\n"),
+ io__write_string("#define MR_USE_REDOFR\n"),
globals__io_get_trace_level(TraceLevel),
( { trace_level_trace_interface(TraceLevel, yes) } ->
io__write_string("#define MR_STACK_TRACE_THIS_MODULE\n"),
@@ -737,7 +742,7 @@
(
Instr = call(_, label(ContLabel), _, _)
;
- Instr = mkframe(_, _, _, label(ContLabel))
+ Instr = mkframe(_, label(ContLabel))
;
Instr = modframe(label(ContLabel))
;
@@ -845,14 +850,19 @@
output_code_addr_decls(Target, "", "", 0, _, DeclSet0, DeclSet1),
output_code_addr_decls(ContLabel, "", "", 0, _, DeclSet1, DeclSet).
output_instruction_decls(c_code(_), DeclSet, DeclSet) --> [].
-output_instruction_decls(mkframe(_, _, MaybeStruct, FailureContinuation),
+output_instruction_decls(mkframe(FrameInfo, FailureContinuation),
DeclSet0, DeclSet) -->
(
- { MaybeStruct = yes(pragma_c_struct(StructName,
- StructFields, MaybeStructFieldsContext)) }
- ->
- { bintree_set__is_member(pragma_c_struct(StructName), DeclSet0) ->
- string__append_list(["struct ", StructName, " has been declared already"], Msg),
+ { FrameInfo = ordinary_frame(_, _, yes(Struct)) },
+ { Struct = pragma_c_struct(StructName, StructFields,
+ MaybeStructFieldsContext) }
+ ->
+ {
+ bintree_set__is_member(pragma_c_struct(StructName),
+ DeclSet0)
+ ->
+ string__append_list(["struct ", StructName,
+ " has been declared already"], Msg),
error(Msg)
;
true
@@ -868,7 +878,8 @@
io__write_string(StructFields)
),
io__write_string("\n};\n"),
- { bintree_set__insert(DeclSet0, pragma_c_struct(StructName), DeclSet1) }
+ { bintree_set__insert(DeclSet0, pragma_c_struct(StructName),
+ DeclSet1) }
;
{ DeclSet1 = DeclSet0 }
),
@@ -1097,23 +1108,31 @@
io__write_string("\t"),
io__write_string(C_Code_String).
-output_instruction(mkframe(Msg, Num, MaybePragmaStructName, FailCont), _) -->
- ( { MaybePragmaStructName = yes(pragma_c_struct(StructName, _, _)) } ->
- io__write_string("\tmkpragmaframe("""),
- io__write_string(Msg),
- io__write_string(""", "),
- io__write_int(Num),
- io__write_string(", "),
- io__write_string(StructName),
- io__write_string(", "),
- output_code_addr(FailCont),
- io__write_string(");\n")
+output_instruction(mkframe(FrameInfo, FailCont), _) -->
+ (
+ { FrameInfo = ordinary_frame(Msg, Num, MaybeStruct) },
+ ( { MaybeStruct = yes(pragma_c_struct(StructName, _, _)) } ->
+ io__write_string("\tmkpragmaframe("""),
+ io__write_string(Msg),
+ io__write_string(""", "),
+ io__write_int(Num),
+ io__write_string(", "),
+ io__write_string(StructName),
+ io__write_string(", "),
+ output_code_addr(FailCont),
+ io__write_string(");\n")
+ ;
+ io__write_string("\tmkframe("""),
+ io__write_string(Msg),
+ io__write_string(""", "),
+ io__write_int(Num),
+ io__write_string(", "),
+ output_code_addr(FailCont),
+ io__write_string(");\n")
+ )
;
- io__write_string("\tmkframe("""),
- io__write_string(Msg),
- io__write_string(""", "),
- io__write_int(Num),
- io__write_string(", "),
+ { FrameInfo = temp_frame },
+ io__write_string("\tmktempframe("),
output_code_addr(FailCont),
io__write_string(");\n")
).
@@ -1503,6 +1522,7 @@
output_live_value_type(succip) --> io__write_string("MR_succip").
output_live_value_type(curfr) --> io__write_string("MR_curfr").
output_live_value_type(maxfr) --> io__write_string("MR_maxfr").
+output_live_value_type(redofr) --> io__write_string("MR_redofr").
output_live_value_type(redoip) --> io__write_string("MR_redoip").
output_live_value_type(hp) --> io__write_string("MR_hp").
output_live_value_type(unwanted) --> io__write_string("unwanted").
@@ -1949,6 +1969,10 @@
DeclSet0, DeclSet) -->
output_rval_decls(Rval, FirstIndent, LaterIndent, N0, N,
DeclSet0, DeclSet).
+output_lval_decls(redofr(Rval), FirstIndent, LaterIndent, N0, N,
+ DeclSet0, DeclSet) -->
+ output_rval_decls(Rval, FirstIndent, LaterIndent, N0, N,
+ DeclSet0, DeclSet).
output_lval_decls(redoip(Rval), FirstIndent, LaterIndent, N0, N,
DeclSet0, DeclSet) -->
output_rval_decls(Rval, FirstIndent, LaterIndent, N0, N,
@@ -3034,6 +3058,10 @@
io__write_string(")").
output_lval(prevfr(Rval)) -->
io__write_string("bt_prevfr("),
+ output_rval(Rval),
+ io__write_string(")").
+output_lval(redofr(Rval)) -->
+ io__write_string("bt_redofr("),
output_rval(Rval),
io__write_string(")").
output_lval(redoip(Rval)) -->
More information about the developers
mailing list