Tabling round 2 [3/3]
Oliver Hutchison
ohutch at students.cs.mu.OZ.AU
Fri Mar 13 16:54:01 AEDT 1998
New File: compiler/table_gen.m
===================================================================
%-----------------------------------------------------------------------------%
% Copyright (C) 1997-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.
%-----------------------------------------------------------------------------%
%
% This module transforms HLDS code to a form that allows tabled evaluation,
% minimal model evaluation and loop detection.
%
% Main author: ohutch
%
% The tabling transformation adds calls to several tabling predicates as
% well as restructuring the HLDS to implement answer clause resolution,
% suspension and loop detection.
%
% Example of transformation for semidet minimal_model :
%
% Given the following code for left recursive transitive closure :
%
% :- pred p(int, int).
% :- mode p(in, in) is semidet.
%
% p(A, B) :- e(A, B).
% p(A, B) :- p(A, C), e(C, B).
%
% The transformed code would be :
%
% p(A, B) :-
% % Code to get a handle on the table
% c_code(T0::out, "
% static Word Table = 0;
% T0 = &Table;
% "),
%
% % Code to lookup input arguments
% impure table_lookup_insert_int(T0, A, T1),
% impure table_lookup_insert_int(T1, B, T2),
% (if
% semipure table_have_ans(T2)
% then
% % True if the subgoal has already succeeded
% semipure table_has_succeeded(T2)
% else
% (if
% % Fail if we are already working on
% % an ans for this subgoal
% semipure table_not_working_on_ans(T2),
%
% % Mark this subgoal as being evaluated
% impure table_mark_as_working(T2),
%
% (
% %
% % Original goals
% %
% )
% then
% impure table_mark_as_succeeded(T2)
% else
% impure table_mark_as_failed(T2)
% )
% ).
%
% Example of transformation for nondet minimal_model :
%
% Given the following code for left recursive transitive closure :
%
% :- pred p(int, int).
% :- mode p(in, out) is nondet
%
% p(A, B) :- e(A, B).
% p(A, B) :- p(A, C), e(C, B).
%
% The transformed code would be :
%
% p(A, B) :-
% % Code to get a handle on the table
% c_code(T0::out, "
% static Word Table = 0;
% T0 = &Table;
% "),
% % Code to lookup input arguments and setup table
% impure table_lookup_insert_int(T0, A, T1),
% impure table_setup(T1, T2),
% (if
% semipure table_have_all_ans(T2)
% then
% % Code to return all ans if we have found
% % them
% impure table_return_all_ans(T2, Ans),
% impure table_restore_int_ans(Ans, 0, B)
% else if
% semipure table_have_some_ans(T2)
% then
% % Code to suspend the current computational
% % branch
% impure table_suspend(T2, Ans),
% impure table_restore_int_ans(Ans, 0, B)
% else
% ( % Mark that this subgoal is being
% % evaluated
% impure table_mark_have_some_ans(T2),
%
% (
% %
% % Original goals
% %
% ),
%
% % Code to check for duplicate
% % answers
% impure table_get_ans_table(T2, AT0),
% impure table_lookup_insert_int(AT0, B, AT1),
%
% % The following pred is semidet
% % it will fail if the answer is
% % already in the table.
% semipure table_new_ans(AT1),
%
% % Code to save a new ans in the
% % table.
% impure table_mark_as_returned(AT1),
% impure table_new_ans_slot(T2, AS),
% impure table_create_ans_block(AS, 1, AB),
% impure table_save_int_ans(AB, 0, B)
% ;
% % Code to resume suspended nodes.
% impure table_resume(T2)
% ;
%
% % Code to mark the current subgoal
% % as totally evaluated.
% impure table_mark_have_all_ans(T2)
% )
% ).
%
% The memo and loopcheck transformations are very similar to the above
% transformations except that for the memo case the code for handing
% loops (fail in the semi_det case, suspend in the nondet case) is dropped.
% And in the loop_check case the code for memoing answers is dropped and the
% loop handling code is modified to call an error predicate.
%
%
%-----------------------------------------------------------------------------%
:- module table_gen.
:- interface.
:- import_module hlds_module.
:- pred table_gen__process_module(module_info, module_info).
:- mode table_gen__process_module(in, out) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_out.
:- import_module hlds_pred, instmap.
:- import_module code_aux, det_analysis, follow_code, goal_util, const_prop.
:- import_module hlds_module, hlds_goal, hlds_data, (inst), inst_match.
:- import_module globals, options, passes_aux, prog_data, mode_util, type_util.
:- import_module code_util, quantification, modes, purity.
:- import_module bool, list, set, map, require, std_util, term, varset, int.
:- import_module assoc_list, string, llds.
%-----------------------------------------------------------------------------%
table_gen__process_module(Module0, Module) :-
module_info_preds(Module0, Preds0),
map__keys(Preds0, PredIds),
table_gen__process_preds(PredIds, Module0, Module).
:- pred table_gen__process_preds(list(pred_id), module_info, module_info).
:- mode table_gen__process_preds(in, in, out) is det.
table_gen__process_preds([], Module, Module).
table_gen__process_preds([PredId | PredIds], Module0, Module) :-
table_gen__process_pred(PredId, Module0, Module1),
table_gen__process_preds(PredIds, Module1, Module).
:- pred table_gen__process_pred(pred_id, module_info, module_info).
:- mode table_gen__process_pred(in, in, out) is det.
table_gen__process_pred(PredId, Module0, Module) :-
module_info_pred_info(Module0, PredId, PredInfo),
pred_info_procids(PredInfo, ProcIds),
table_gen__process_procs(PredId, ProcIds, Module0, Module).
:- pred table_gen__process_procs(pred_id, list(proc_id),
module_info, module_info).
:- mode table_gen__process_procs(in, in, in, out) is det.
table_gen__process_procs(_PredId, [], Module, Module).
table_gen__process_procs(PredId, [ProcId | ProcIds], Module0,
Module) :-
module_info_preds(Module0, PredTable),
map__lookup(PredTable, PredId, PredInfo),
pred_info_procedures(PredInfo, ProcTable),
map__lookup(ProcTable, ProcId, ProcInfo),
proc_info_eval_method(ProcInfo, EvalMethod),
(
EvalMethod \= eval_normal
->
table_gen__process_proc(EvalMethod, PredId, ProcId, ProcInfo,
PredInfo, Module0, Module1)
;
Module1 = Module0
),
table_gen__process_procs(PredId, ProcIds, Module1, Module).
%---------------------------------------------------------------------------%
:- pred table_gen__process_proc(eval_method, pred_id, proc_id, proc_info,
pred_info, module_info, module_info).
:- mode table_gen__process_proc(in, in, in, in, in, in, out) is det.
table_gen__process_proc(EvalMethod, PredId, ProcId, ProcInfo0, PredInfo0,
Module0, Module) :-
% grab the appropriate fields from the pred_info and proc_info
pred_info_name(PredInfo, _PredName),
proc_info_interface_code_model(ProcInfo0, CodeModel),
proc_info_headvars(ProcInfo0, HeadVars),
proc_info_varset(ProcInfo0, VarSet0),
proc_info_vartypes(ProcInfo0, VarTypes0),
proc_info_goal(ProcInfo0, OrigGoal),
proc_info_argmodes(ProcInfo0, ArgModes),
(
CodeModel = model_det,
table_gen__create_new_det_goal(EvalMethod, OrigGoal,
Module0, HeadVars, ArgModes, VarTypes0, VarTypes,
VarSet0, VarSet, Goal)
;
CodeModel = model_semi,
table_gen__create_new_semi_goal(EvalMethod, OrigGoal,
Module0, HeadVars, ArgModes, VarTypes0, VarTypes,
VarSet0, VarSet, Goal)
;
CodeModel = model_non,
table_gen__create_new_non_goal(EvalMethod, OrigGoal,
Module0, HeadVars, ArgModes, VarTypes0, VarTypes,
VarSet0, VarSet, Goal)
),
% set the new values of the fields in proc_info and pred_info
% and save in the module info
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
proc_info_set_varset(ProcInfo1, VarSet, ProcInfo2),
proc_info_set_vartypes(ProcInfo2, VarTypes, ProcInfo),
pred_info_procedures(PredInfo0, ProcTable1),
map__det_update(ProcTable1, ProcId, ProcInfo, ProcTable),
pred_info_set_procedures(PredInfo0, ProcTable, PredInfo),
module_info_preds(Module0, PredTable0),
map__det_update(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(Module0, PredTable, Module).
%------------------------------------------------------------------------------%
%
% Transform deterministic procedures.
%
:- pred table_gen__create_new_det_goal(eval_method, hlds_goal, module_info,
list(var), list(mode), map(var, type), map(var, type),
varset, varset, hlds_goal).
:- mode table_gen__create_new_det_goal(in, in, in, in, in, in, out, in,
out, out) is det.
table_gen__create_new_det_goal(EvalMethod, OrigGoal, Module, HeadVars,
HeadVarModes, VarTypes0, VarTypes, VarSet0, VarSet, Goal) :-
get_input_output_vars(HeadVars, HeadVarModes, Module, InputVars,
OutputVars),
generate_det_lookup_goal(InputVars, Module, VarTypes0, VarTypes1,
VarSet0, VarSet1, TableVar, LookUpGoal),
generate_call("table_have_ans", [TableVar], semidet, semipure,
[], Module, HaveAnsCheckGoal),
generate_save_goal(OutputVars, TableVar, VarTypes1, VarTypes2,
VarSet1, VarSet2, Module, SaveAnsGoal0),
generate_restore_goal(OutputVars, TableVar, Module, VarTypes2,
VarTypes, VarSet2, VarSet, RestoreAnsGoal),
generate_call("table_mark_done_working", [TableVar], det, impure,
[], Module, DoneWorkingGoal),
OrigGoal = _ - OrigGoalInfo,
goal_info_get_nonlocals(OrigGoalInfo, OrigNonLocals),
goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
set__insert(OrigNonLocals, TableVar, GenAnsNonLocals),
map__init(StoreMap),
(
(
EvalMethod = eval_memo
;
EvalMethod = eval_loop_check
)
->
(
EvalMethod = eval_loop_check
->
SaveAnsGoal = DoneWorkingGoal
;
SaveAnsGoal = SaveAnsGoal0
),
generate_call("table_working_on_ans", [TableVar], semidet,
semipure, [], Module, WorkingCheckGoal),
generate_call("table_loopcheck_error", [], erroneous, impure,
[], Module, LoopErrorGoal),
generate_call("table_mark_as_working", [TableVar], det,
impure, [], Module, MarkAsWorkingGoal),
NoLoopGenAnsGoalEx = conj([MarkAsWorkingGoal, OrigGoal,
SaveAnsGoal]),
create_instmap_delta([MarkAsWorkingGoal, OrigGoal,
SaveAnsGoal], NoLoopGenInstMapDelta0),
instmap_delta_restrict(NoLoopGenInstMapDelta0, GenAnsNonLocals,
NoLoopGenInstMapDelta),
goal_info_init(GenAnsNonLocals, NoLoopGenInstMapDelta, det,
NoLoopGenGoalInfo),
NoLoopGenAnsGoal = NoLoopGenAnsGoalEx - NoLoopGenGoalInfo,
GenAnsGoalEx = if_then_else([], WorkingCheckGoal,
LoopErrorGoal, NoLoopGenAnsGoal, StoreMap),
create_instmap_delta([WorkingCheckGoal, LoopErrorGoal,
NoLoopGenAnsGoal], GenAnsInstMapDelta0),
instmap_delta_restrict(GenAnsInstMapDelta0, GenAnsNonLocals,
GenAnsInstMapDelta),
goal_info_init(GenAnsNonLocals, GenAnsInstMapDelta, det,
GenAnsGoalInfo),
GenAnsGoal = GenAnsGoalEx - GenAnsGoalInfo
;
error(
"table_gen__create_new_det_goal: unsupported evaluation model")
),
ITEGoalEx = if_then_else([], HaveAnsCheckGoal, RestoreAnsGoal,
GenAnsGoal, StoreMap),
create_instmap_delta([HaveAnsCheckGoal, RestoreAnsGoal, GenAnsGoal],
ITEInstMapDelta0),
instmap_delta_restrict(ITEInstMapDelta0, GenAnsNonLocals,
ITEInstMapDelta),
goal_info_init(GenAnsNonLocals, ITEInstMapDelta, det,
ITEGoalInfo),
ITEGoal = ITEGoalEx - ITEGoalInfo,
GoalEx = conj([LookUpGoal, ITEGoal]),
goal_info_init(OrigNonLocals, OrigInstMapDelta, det, GoalInfo),
Goal = GoalEx - GoalInfo.
%------------------------------------------------------------------------------%
%
% Transform semi deterministic procedures
%
:- pred table_gen__create_new_semi_goal(eval_method, hlds_goal,
module_info, list(var), list(mode), map(var, type),
map(var, type), varset, varset, hlds_goal).
:- mode table_gen__create_new_semi_goal(in, in, in, in, in, in, out, in,
out, out) is det.
table_gen__create_new_semi_goal(EvalMethod, OrigGoal, Module, HeadVars,
HeadVarModes, VarTypes0, VarTypes, VarSet0, VarSet, Goal) :-
get_input_output_vars(HeadVars, HeadVarModes, Module, InputVars,
OutputVars),
generate_det_lookup_goal(InputVars, Module, VarTypes0, VarTypes1,
VarSet0, VarSet1, TableVar, LookUpGoal),
generate_call("table_have_ans", [TableVar], semidet, semipure,
[], Module, HaveAnsCheckGoal),
generate_save_goal(OutputVars, TableVar, VarTypes1, VarTypes2,
VarSet1, VarSet2, Module, SaveAnsGoal0),
generate_restore_goal(OutputVars, TableVar, Module, VarTypes2,
VarTypes, VarSet2, VarSet, RestoreTrueAnsGoal),
generate_call("table_mark_as_failed", [TableVar], failure, impure,
[], Module, MarkAsFailedGoal),
generate_call("table_has_succeeded", [TableVar], semidet, semipure,
[], Module, HasSucceededCheckGoal),
generate_call("table_mark_done_working", [TableVar], det, impure,
[], Module, DoneWorkingGoal),
OrigGoal = _ - OrigGoalInfo,
goal_info_get_nonlocals(OrigGoalInfo, OrigNonLocals),
goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
set__insert(OrigNonLocals, TableVar, GenAnsNonLocals),
map__init(StoreMap),
(
(
EvalMethod = eval_loop_check
;
EvalMethod = eval_memo
)
->
(
EvalMethod = eval_loop_check
->
SaveAnsGoal = DoneWorkingGoal
;
SaveAnsGoal = SaveAnsGoal0
),
generate_call("table_working_on_ans", [TableVar], semidet,
semipure, [], Module, WorkingCheckGoal),
generate_call("table_loopcheck_error", [], erroneous, impure,
[], Module, LoopErrorGoal),
generate_call("table_mark_as_working", [TableVar], det,
impure, [], Module, MarkAsWorkingGoal),
NoLoopGenAnsGoalEx = conj([MarkAsWorkingGoal, OrigGoal]),
create_instmap_delta([MarkAsWorkingGoal, OrigGoal],
NoLoopGenInstMapDelta0),
instmap_delta_restrict(NoLoopGenInstMapDelta0, GenAnsNonLocals,
NoLoopGenInstMapDelta),
goal_info_init(GenAnsNonLocals, NoLoopGenInstMapDelta, semidet,
NoLoopGenGoalInfo),
NoLoopGenAnsGoal = NoLoopGenAnsGoalEx - NoLoopGenGoalInfo,
GenTrueAnsGoalEx = if_then_else([], WorkingCheckGoal,
LoopErrorGoal, NoLoopGenAnsGoal, StoreMap),
create_instmap_delta([WorkingCheckGoal, LoopErrorGoal,
NoLoopGenAnsGoal], GenTrueAnsInstMapDelta0),
instmap_delta_restrict(GenTrueAnsInstMapDelta0,
GenAnsNonLocals, GenTrueAnsInstMapDelta),
goal_info_init(GenAnsNonLocals, GenTrueAnsInstMapDelta,
semidet, GenTrueAnsGoalInfo),
GenTrueAnsGoal = GenTrueAnsGoalEx - GenTrueAnsGoalInfo
;
EvalMethod = eval_minimal
->
SaveAnsGoal = SaveAnsGoal0,
generate_call("table_not_working_on_ans", [TableVar], semidet,
semipure, [], Module, NotWorkingCheckGoal),
generate_call("table_mark_as_working", [TableVar], det,
impure, [], Module, MarkAsWorkingGoal),
GenTrueAnsGoalEx = conj([NotWorkingCheckGoal,
MarkAsWorkingGoal, OrigGoal]),
create_instmap_delta([NotWorkingCheckGoal, MarkAsWorkingGoal,
OrigGoal, SaveAnsGoal], GenTrueAnsInstMapDelta0),
instmap_delta_restrict(GenTrueAnsInstMapDelta0,
GenAnsNonLocals, GenTrueAnsInstMapDelta),
goal_info_init(GenAnsNonLocals, GenTrueAnsInstMapDelta,
semidet, GenTrueAnsGoalInfo),
GenTrueAnsGoal = GenTrueAnsGoalEx - GenTrueAnsGoalInfo
;
error(
"table_gen__create_new_semi_goal: unsupported evaluation model")
),
RestAnsGoalEx = conj([HasSucceededCheckGoal, RestoreTrueAnsGoal]),
set__singleton_set(RestNonLocals0, TableVar),
set__insert_list(RestNonLocals0, OutputVars, RestNonLocals),
create_instmap_delta([HasSucceededCheckGoal, RestoreTrueAnsGoal],
RestInstMapDelta0),
instmap_delta_restrict(RestInstMapDelta0, RestNonLocals,
RestInstMapDelta),
goal_info_init(RestNonLocals, RestInstMapDelta, semidet,
RestAnsGoalInfo),
RestoreAnsGoal = RestAnsGoalEx - RestAnsGoalInfo,
GenAnsGoalEx = if_then_else([], GenTrueAnsGoal, SaveAnsGoal,
MarkAsFailedGoal, StoreMap),
create_instmap_delta([GenTrueAnsGoal, SaveAnsGoal, MarkAsFailedGoal],
GenAnsGoalInstMapDelta0),
instmap_delta_restrict(GenAnsGoalInstMapDelta0, GenAnsNonLocals,
GenAnsGoalInstMapDelta),
goal_info_init(GenAnsNonLocals, GenAnsGoalInstMapDelta, semidet,
GenAnsGoalInfo),
GenAnsGoal = GenAnsGoalEx - GenAnsGoalInfo,
ITEGoalEx = if_then_else([], HaveAnsCheckGoal, RestoreAnsGoal,
GenAnsGoal, StoreMap),
create_instmap_delta([HaveAnsCheckGoal, RestoreAnsGoal, GenAnsGoal],
ITEInstMapDelta0),
instmap_delta_restrict(ITEInstMapDelta0, GenAnsNonLocals,
ITEInstMapDelta),
goal_info_init(GenAnsNonLocals, ITEInstMapDelta, semidet,
ITEGoalInfo),
ITEGoal = ITEGoalEx - ITEGoalInfo,
GoalEx = conj([LookUpGoal, ITEGoal]),
goal_info_init(OrigNonLocals, OrigInstMapDelta, semidet, GoalInfo),
Goal = GoalEx - GoalInfo.
%------------------------------------------------------------------------------%
%
% Transform non deterministic procedures
%
:- pred table_gen__create_new_non_goal(eval_method, hlds_goal, module_info,
list(var), list(mode), map(var, type), map(var, type),
varset, varset, hlds_goal).
:- mode table_gen__create_new_non_goal(in, in, in, in, in, in, out, in,
out, out) is det.
table_gen__create_new_non_goal(EvalMethod, OrigGoal, Module, HeadVars,
HeadVarModes, VarTypes0, VarTypes, VarSet0, VarSet, Goal) :-
get_input_output_vars(HeadVars, HeadVarModes, Module, InputVars,
OutputVars),
generate_non_lookup_goal(InputVars, Module, VarTypes0, VarTypes1,
VarSet0, VarSet1, TableVar, LookUpGoal),
generate_call("table_have_all_ans", [TableVar], semidet, semipure,
[], Module, HaveAllAnsCheckGoal),
generate_non_save_goal(OutputVars, TableVar, VarTypes1, VarTypes2,
VarSet1, VarSet2, Module, SaveAnsGoal0),
generate_restore_all_goal(OutputVars, TableVar, Module, VarTypes2,
VarTypes3, VarSet2, VarSet3, RestoreAllAnsGoal),
generate_call("table_have_some_ans", [TableVar], semidet, semipure,
[], Module, HaveSomeAnsCheckGoal),
generate_suspend_goal(OutputVars, TableVar, Module, VarTypes3,
VarTypes, VarSet3, VarSet, SuspendGoal),
generate_call("table_mark_have_some_ans", [TableVar], det, impure,
[], Module, MarkHaveSomeAnsGoal),
generate_call("table_resume", [TableVar], failure, impure,
[], Module, ResumeGoal0),
generate_call("table_mark_have_all_ans", [TableVar], failure, impure,
[], Module, MarkHaveAllAnsGoal),
generate_call("table_loopcheck_error", [], erroneous, impure,
[], Module, LoopErrorGoal),
generate_call("table_mark_done_working", [TableVar], det, impure,
[], Module, DoneWorkingGoal),
fail_goal(FailGoal),
OrigGoal = _ - OrigGoalInfo,
goal_info_get_nonlocals(OrigGoalInfo, OrigNonLocals),
goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
map__init(StoreMap),
(
(
EvalMethod = eval_memo
;
EvalMethod = eval_loop_check
)
->
(
EvalMethod = eval_loop_check
->
SaveAnsGoal = DoneWorkingGoal
;
SaveAnsGoal = SaveAnsGoal0
),
WorkingOnAnsGoal = LoopErrorGoal
;
EvalMethod = eval_minimal
->
SaveAnsGoal = SaveAnsGoal0,
WorkingOnAnsGoal = SuspendGoal
;
error(
"table_gen__create_new_non_goal: unsupported evaluation model")
),
GenAnsGoalPart1Ex = conj([MarkHaveSomeAnsGoal, OrigGoal, SaveAnsGoal]),
set__insert(OrigNonLocals, TableVar, GenAnsGoalPart1NonLocals),
create_instmap_delta([MarkHaveSomeAnsGoal, OrigGoal, SaveAnsGoal],
GenAnsGoalPart1IMD0),
instmap_delta_restrict(GenAnsGoalPart1IMD0, GenAnsGoalPart1NonLocals,
GenAnsGoalPart1IMD),
goal_info_init(GenAnsGoalPart1NonLocals, GenAnsGoalPart1IMD, nondet,
GenAnsGoalPart1GoalInfo),
GenAnsGoalPart1 = GenAnsGoalPart1Ex - GenAnsGoalPart1GoalInfo,
(
(
EvalMethod = eval_minimal
;
EvalMethod = eval_memo
)
->
(
EvalMethod = eval_minimal
->
ResumeGoal = ResumeGoal0
;
ResumeGoal = FailGoal
),
GenAnsGoalEx = disj([GenAnsGoalPart1, ResumeGoal,
MarkHaveAllAnsGoal], StoreMap),
create_instmap_delta([GenAnsGoalPart1, ResumeGoal,
MarkHaveAllAnsGoal], GenAnsIMD0),
instmap_delta_restrict(GenAnsIMD0, GenAnsGoalPart1NonLocals,
GenAnsIMD),
goal_info_init(GenAnsGoalPart1NonLocals, GenAnsIMD, nondet,
GenAnsGoalInfo),
GenAnsGoal = GenAnsGoalEx - GenAnsGoalInfo
;
GenAnsGoal = GenAnsGoalPart1
),
ITE1GoalEx = if_then_else([], HaveSomeAnsCheckGoal, WorkingOnAnsGoal,
GenAnsGoal, StoreMap),
ITE1Goal = ITE1GoalEx - GenAnsGoalPart1GoalInfo,
ITE2GoalEx = if_then_else([], HaveAllAnsCheckGoal, RestoreAllAnsGoal,
ITE1Goal, StoreMap),
ITE2Goal = ITE2GoalEx - GenAnsGoalPart1GoalInfo,
GoalEx = conj([LookUpGoal, ITE2Goal]),
goal_info_init(OrigNonLocals, OrigInstMapDelta, nondet, GoalInfo),
Goal = GoalEx - GoalInfo.
%------------------------------------------------------------------------------%
:- pred generate_get_table_goals(map(var, type), map(var, type), varset,
varset, module_info, var, hlds_goal).
:- mode generate_get_table_goals(in, out, in, out, in, out, out) is det.
generate_get_table_goals(VarTypes0, VarTypes, VarSet0, VarSet, Module,
TableVar, Goal) :-
generate_new_table_var(VarTypes0, VarTypes, VarSet0, VarSet,
TableVar),
% The predicate get_table/1 is used only for its pred_proc_id
% the code is not actualy called. We have to steal the
% pred_proc_id for the c_code instruction below.
module_info_get_predicate_table(Module, PredTable),
(
predicate_table_search_pred_m_n_a(PredTable,
unqualified("mercury_builtin"), "get_table", 1,
[PredId0])
->
PredId = PredId0
;
error("can't locate mercury_builtin:get_table/1")
),
module_info_pred_info(Module, PredId, PredInfo),
(
pred_info_procids(PredInfo, [ProcId0])
->
ProcId = ProcId0
;
error(
"too many modes for predicate mercury_builtin:get_table/1")
),
TableVarInst = ground(unique, no),
TableVarMode = (free -> TableVarInst),
get_table_var_type(TableVarType),
GoalEx = pragma_c_code(will_not_call_mercury, PredId, ProcId,
[TableVar], [yes("TableVar" - TableVarMode)],
[TableVarType], ordinary(
" {
static Word Table = 0;
TableVar = (Word)&Table;
}
",
no)),
set__singleton_set(NonLocals, TableVar),
instmap_delta_from_assoc_list([TableVar - TableVarInst],
InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, det,
GoalInfo0),
goal_info_add_feature(GoalInfo0, impure, GoalInfo),
Goal = GoalEx - GoalInfo.
%------------------------------------------------------------------------------%
:- pred generate_det_lookup_goal(list(var), module_info, map(var, type),
map(var, type), varset, varset, var, hlds_goal).
:- mode generate_det_lookup_goal(in, in, in, out, in, out, out, out) is det.
generate_det_lookup_goal(Vars, Module, VarTypes0, VarTypes, VarSet0, VarSet,
TableVar, Goal) :-
generate_get_table_goals(VarTypes0, VarTypes1, VarSet0, VarSet1, Module,
TableVar0, GetTableGoal),
generate_lookup_goals(Vars, TableVar0, TableVar, Module,
VarTypes1, VarTypes, VarSet1, VarSet, LookupGoals),
GoalEx = conj([GetTableGoal | LookupGoals]),
set__singleton_set(NonLocals0, TableVar),
set__insert_list(NonLocals0, Vars, NonLocals),
instmap_delta_from_assoc_list([], InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, det, GoalInfo),
Goal = GoalEx - GoalInfo.
:- pred generate_non_lookup_goal(list(var), module_info, map(var, type),
map(var, type), varset, varset, var, hlds_goal).
:- mode generate_non_lookup_goal(in, in, in, out, in, out, out, out) is det.
generate_non_lookup_goal(Vars, Module, VarTypes0, VarTypes, VarSet0, VarSet,
TableVar, Goal) :-
generate_get_table_goals(VarTypes0, VarTypes1, VarSet0, VarSet1, Module,
TableVar0, GetTableGoal),
generate_lookup_goals(Vars, TableVar0, TableVar1, Module,
VarTypes1, VarTypes2, VarSet1, VarSet2, LookupGoals),
generate_new_table_var(VarTypes2, VarTypes, VarSet2, VarSet,
TableVar),
generate_call("table_setup", [TableVar1, TableVar], det, impure,
[TableVar - ground(unique, no)], Module, SetupGoal),
list__append([GetTableGoal | LookupGoals], [SetupGoal], Goals),
GoalEx = conj(Goals),
set__singleton_set(NonLocals0, TableVar),
set__insert_list(NonLocals0, Vars, NonLocals),
create_instmap_delta(Goals, InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, det, GoalInfo),
Goal = GoalEx - GoalInfo.
:- pred generate_lookup_goals(list(var), var, var, module_info,
map(var, type), map(var, type), varset, varset,
list(hlds_goal)).
:- mode generate_lookup_goals(in, in, out, in, in, out, in, out, out) is det.
generate_lookup_goals([], TableVar, TableVar, _, VarTypes, VarTypes, VarSet,
VarSet, []).
generate_lookup_goals([Var|Rest], TableVar0, TableVar, Module, VarTypes0,
VarTypes, VarSet0, VarSet, [Goal|RestGoals]) :-
map__lookup(VarTypes0, Var, VarType),
classify_type(VarType, Module, TypeCat),
gen_lookup_call_for_type(TypeCat, VarType, TableVar0, Var,
Module, VarTypes0, VarTypes1, VarSet0, VarSet1, TableVar1,
Goal),
generate_lookup_goals(Rest, TableVar1, TableVar, Module,
VarTypes1, VarTypes, VarSet1, VarSet, RestGoals).
:- pred gen_lookup_call_for_type(builtin_type, type, var, var, module_info,
map(var, type), map(var, type), varset, varset, var,
hlds_goal).
:- mode gen_lookup_call_for_type(in, in, in, in, in, in, out, in,
out, out, out) is det.
gen_lookup_call_for_type(TypeCat, Type, TableVar, ArgVar, Module, VarTypes0,
VarTypes, VarSet0, VarSet, NextTableVar, Goal) :-
(
TypeCat = enum_type
->
(
type_to_type_id(Type, TypeId, _)
->
module_info_types(Module, TypeDefnTable),
map__lookup(TypeDefnTable, TypeId, TypeDefn),
hlds_data__get_type_defn_body(TypeDefn, TypeBody),
(
TypeBody = du_type(Ctors, _, yes, no)
->
list__length(Ctors, EnumRange)
;
error(
"gen_lookup_call_for_type: unsupported type in tabled predicate/function")
),
gen_int_construction("RangeVar", EnumRange, VarTypes0,
VarTypes1, VarSet0, VarSet1, RangeVar,
RangeUnifyGoal),
generate_new_table_var(VarTypes1, VarTypes, VarSet1,
VarSet, NextTableVar),
generate_call("table_lookup_insert_enum", [TableVar,
RangeVar, ArgVar, NextTableVar], det, impure,
[NextTableVar - ground(unique, no)], Module,
LookupGoal),
set__init(NonLocals0),
set__insert_list(NonLocals0, [TableVar, ArgVar],
NonLocals),
instmap_delta_from_assoc_list([], InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, det, GoalInfo),
Goal = conj([RangeUnifyGoal, LookupGoal]) - GoalInfo
;
error("gen_lookup: unexpected type")
)
;
(
(
TypeCat = pred_type
;
TypeCat = polymorphic_type
;
TypeCat = user_type
)
->
(
term__vars(Type, [])
->
LookupPredName = "table_lookup_insert_user"
;
LookupPredName = "table_lookup_insert_poly"
)
;
builtin_type_to_string(TypeCat, CatString),
string__append("table_lookup_insert_", CatString,
LookupPredName)
),
generate_new_table_var(VarTypes0, VarTypes, VarSet0, VarSet,
NextTableVar),
generate_call(LookupPredName, [TableVar, ArgVar, NextTableVar],
det, impure, [NextTableVar - ground(unique, no)],
Module, Goal)
).
%------------------------------------------------------------------------------%
:- pred generate_save_goal(list(var), var, map(var, type), map(var, type),
varset, varset, module_info, hlds_goal).
:- mode generate_save_goal(in, in, in, out, in, out, in, out) is det.
generate_save_goal(AnsList, TableVar, VarTypes0, VarTypes, VarSet0,
VarSet, Module, Goal) :-
list__length(AnsList, NumAnsVars),
(
NumAnsVars \= 0
->
gen_int_construction("NumAnsVars", NumAnsVars, VarTypes0,
VarTypes1, VarSet0, VarSet1, NumAnsVarsVar,
NumAnsVarsUnifyGoal),
generate_new_table_var(VarTypes1, VarTypes2, VarSet1, VarSet2,
AnsTableVar),
generate_call("table_create_ans_block", [TableVar,
NumAnsVarsVar, AnsTableVar], det, impure,
[AnsTableVar - ground(unique, no)], Module,
GenAnsBlockGoal),
generate_save_goals(AnsList, AnsTableVar, 0, Module,
VarTypes2, VarTypes, VarSet2, VarSet, SaveGoals),
GoalEx = conj([NumAnsVarsUnifyGoal, GenAnsBlockGoal |
SaveGoals]),
set__singleton_set(NonLocals0, TableVar),
set__insert_list(NonLocals0, AnsList, NonLocals),
create_instmap_delta([NumAnsVarsUnifyGoal, GenAnsBlockGoal |
SaveGoals], InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, det, GoalInfo),
Goal = GoalEx - GoalInfo
;
VarTypes = VarTypes0,
VarSet = VarSet0,
generate_call("table_mark_as_succeeded", [TableVar], det,
impure, [], Module, Goal)
).
:- pred generate_non_save_goal(list(var), var, map(var, type), map(var, type),
varset, varset, module_info, hlds_goal).
:- mode generate_non_save_goal(in, in, in, out, in, out, in, out) is det.
generate_non_save_goal(AnsList, TableVar, VarTypes0, VarTypes, VarSet0,
VarSet, Module, Goal) :-
generate_new_table_var(VarTypes0, VarTypes1, VarSet0, VarSet1,
AnsTableVar0),
generate_call("table_get_ans_table", [TableVar, AnsTableVar0], det,
impure, [AnsTableVar0 - ground(unique, no)], Module,
GetAnsTableGoal),
generate_lookup_goals(AnsList, AnsTableVar0, AnsTableVar1, Module,
VarTypes1, VarTypes2, VarSet1, VarSet2, LookupAnsGoals),
generate_call("table_new_ans", [AnsTableVar1], semidet, semipure,
[], Module, NewAnsCheckGoal),
generate_call("table_mark_as_returned", [AnsTableVar1], det, impure,
[], Module, MarkAsReturnedGoal),
generate_new_table_var(VarTypes2, VarTypes3, VarSet2, VarSet3,
AnsBlockVar0),
generate_call("table_new_ans_slot", [TableVar, AnsBlockVar0], det,
impure, [AnsBlockVar0 - ground(unique, no)], Module,
GenAnsSlotGoal),
list__length(AnsList, NumAnsVars),
gen_int_construction("NumAnsVars", NumAnsVars, VarTypes3, VarTypes4,
VarSet3, VarSet4, NumAnsVarsVar, NumAnsVarsUnifyGoal),
generate_new_table_var(VarTypes4, VarTypes5, VarSet4, VarSet5,
AnsBlockVar),
generate_call("table_create_ans_block", [AnsBlockVar0, NumAnsVarsVar,
AnsBlockVar], det, impure, [AnsBlockVar - ground(unique, no)],
Module, GenAnsBlockGoal),
generate_save_goals(AnsList, AnsBlockVar, 0, Module, VarTypes5,
VarTypes, VarSet5, VarSet, SaveGoals),
list__append([GetAnsTableGoal | LookupAnsGoals],
[NewAnsCheckGoal, MarkAsReturnedGoal, GenAnsSlotGoal,
NumAnsVarsUnifyGoal, GenAnsBlockGoal | SaveGoals], Goals),
GoalEx = conj(Goals),
set__singleton_set(NonLocals0, TableVar),
set__insert_list(NonLocals0, AnsList, NonLocals),
create_instmap_delta(Goals, InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, semidet, GoalInfo),
Goal = GoalEx - GoalInfo.
:- pred generate_save_goals(list(var), var, int, module_info, map(var, type),
map(var, type), varset, varset, list(hlds_goal)).
:- mode generate_save_goals(in, in, in, in, in, out, in, out, out) is det.
generate_save_goals([], _TableVar, _Offset, _Module, VarTypes, VarTypes,
VarSet, VarSet, []).
generate_save_goals([Var|Rest], TableVar, Offset0, Module, VarTypes0,
VarTypes, VarSet0, VarSet, [OffsetUnifyGoal,
CallGoal|RestGoals]) :-
gen_int_construction("OffsetVar", Offset0, VarTypes0, VarTypes1,
VarSet0, VarSet1, OffsetVar, OffsetUnifyGoal),
map__lookup(VarTypes1, Var, VarType),
classify_type(VarType, Module, TypeCat),
gen_save_call_for_type(TypeCat, VarType, TableVar, Var, OffsetVar,
Module, CallGoal),
Offset is Offset0 + 1,
generate_save_goals(Rest, TableVar, Offset, Module, VarTypes1,
VarTypes, VarSet1, VarSet, RestGoals).
:- pred gen_save_call_for_type(builtin_type, type, var, var, var, module_info,
hlds_goal).
:- mode gen_save_call_for_type(in, in, in, in, in, in, out) is det.
gen_save_call_for_type(TypeCat, _Type, TableVar, Var, OffsetVar, Module,
Goal) :-
(
(
TypeCat = pred_type
;
TypeCat = enum_type
;
TypeCat = polymorphic_type
;
TypeCat = user_type
)
->
LookupPredName = "table_save_any_ans"
;
builtin_type_to_string(TypeCat, CatString),
string__append_list(["table_save_", CatString, "_ans"],
LookupPredName)
),
generate_call(LookupPredName, [TableVar, OffsetVar, Var],
det, impure, [], Module, Goal).
%------------------------------------------------------------------------------%
:- pred generate_restore_goal(list(var), var, module_info, map(var, type),
map(var, type), varset, varset, hlds_goal).
:- mode generate_restore_goal(in, in, in, in, out, in, out, out) is det.
generate_restore_goal(OutputVars, TableVar, Module, VarTypes0, VarTypes,
VarSet0, VarSet, Goal) :-
generate_restore_goals(OutputVars, TableVar, 0, Module, VarTypes0,
VarTypes, VarSet0, VarSet, RestoreGoals),
GoalEx = conj(RestoreGoals),
set__singleton_set(NonLocals0, TableVar),
set__insert_list(NonLocals0, OutputVars, NonLocals),
create_instmap_delta(RestoreGoals, InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, det,
GoalInfo),
Goal = GoalEx - GoalInfo.
:- pred generate_restore_all_goal(list(var), var, module_info, map(var, type),
map(var, type), varset, varset, hlds_goal).
:- mode generate_restore_all_goal(in, in, in, in, out, in, out, out) is det.
generate_restore_all_goal(OutputVars, TableVar, Module, VarTypes0, VarTypes,
VarSet0, VarSet, Goal) :-
generate_new_table_var(VarTypes0, VarTypes1, VarSet0, VarSet1,
AnsTableVar),
generate_call("table_return_all_ans", [TableVar, AnsTableVar],
nondet, semipure, [AnsTableVar - ground(unique, no)],
Module, ReturnAnsBlocksGoal),
generate_restore_goals(OutputVars, AnsTableVar, 0, Module, VarTypes1,
VarTypes, VarSet1, VarSet, RestoreGoals),
GoalEx = conj([ReturnAnsBlocksGoal | RestoreGoals]),
set__singleton_set(NonLocals0, TableVar),
set__insert_list(NonLocals0, OutputVars, NonLocals),
create_instmap_delta([ReturnAnsBlocksGoal | RestoreGoals],
InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, nondet,
GoalInfo),
Goal = GoalEx - GoalInfo.
:- pred generate_restore_goals(list(var), var, int, module_info, map(var, type),
map(var, type), varset, varset, list(hlds_goal)).
:- mode generate_restore_goals(in, in, in, in, in, out, in, out, out) is det.
generate_restore_goals([], _TableVar, _Offset, _Module, VarTypes, VarTypes,
VarSet, VarSet, []).
generate_restore_goals([Var|Rest], TableVar, Offset0, Module, VarTypes0,
VarTypes, VarSet0, VarSet, [OffsetUnifyGoal,
CallGoal|RestGoals]) :-
gen_int_construction("OffsetVar", Offset0, VarTypes0, VarTypes1,
VarSet0, VarSet1, OffsetVar, OffsetUnifyGoal),
map__lookup(VarTypes1, Var, VarType),
classify_type(VarType, Module, TypeCat),
gen_restore_call_for_type(TypeCat, VarType, TableVar, Var, OffsetVar,
Module, CallGoal),
Offset is Offset0 + 1,
generate_restore_goals(Rest, TableVar, Offset, Module, VarTypes1,
VarTypes, VarSet1, VarSet, RestGoals).
:- pred gen_restore_call_for_type(builtin_type, type, var, var, var,
module_info, hlds_goal).
:- mode gen_restore_call_for_type(in, in, in, in, in, in, out) is det.
gen_restore_call_for_type(TypeCat, _Type, TableVar, Var, OffsetVar, Module,
Goal) :-
(
(
TypeCat = pred_type
;
TypeCat = enum_type
;
TypeCat = polymorphic_type
;
TypeCat = user_type
)
->
LookupPredName = "table_restore_any_ans"
;
builtin_type_to_string(TypeCat, CatString),
string__append_list(["table_restore_", CatString, "_ans"],
LookupPredName)
),
generate_call(LookupPredName, [TableVar, OffsetVar, Var],
det, impure, [Var - ground(shared, no)], Module, Goal).
%------------------------------------------------------------------------------%
:- pred generate_suspend_goal(list(var), var, module_info, map(var, type),
map(var, type), varset, varset, hlds_goal).
:- mode generate_suspend_goal(in, in, in, in, out, in, out, out) is det.
generate_suspend_goal(OutputVars, TableVar, Module, VarTypes0, VarTypes,
VarSet0, VarSet, Goal) :-
generate_new_table_var(VarTypes0, VarTypes1, VarSet0, VarSet1,
AnsTableVar),
generate_call("table_suspend", [TableVar, AnsTableVar],
nondet, semipure, [AnsTableVar - ground(unique, no)],
Module, ReturnAnsBlocksGoal),
generate_restore_goals(OutputVars, AnsTableVar, 0, Module, VarTypes1,
VarTypes, VarSet1, VarSet, RestoreGoals),
GoalEx = conj([ReturnAnsBlocksGoal | RestoreGoals]),
set__singleton_set(NonLocals0, TableVar),
set__insert_list(NonLocals0, OutputVars, NonLocals),
create_instmap_delta([ReturnAnsBlocksGoal | RestoreGoals],
InstMapDelta0),
instmap_delta_restrict(InstMapDelta0, NonLocals, InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, nondet,
GoalInfo),
Goal = GoalEx - GoalInfo.
%------------------------------------------------------------------------------%
:- pred generate_new_table_var(map(var, type), map(var, type), varset, varset,
var).
:- mode generate_new_table_var(in, out, in, out, out) is det.
generate_new_table_var(VarTypes0, VarTypes, VarSet0, VarSet, Var) :-
varset__new_named_var(VarSet0, "TableVar", Var, VarSet),
get_table_var_type(Type),
map__set(VarTypes0, Var, Type, VarTypes).
:- pred generate_call(string, list(var), determinism, goal_feature,
assoc_list(var, inst), module_info, hlds_goal).
:- mode generate_call(in, in, in, in, in, in, out) is det.
generate_call(PredName, Args, Detism, Feature, InstMap, Module, Goal) :-
list__length(Args, Arity),
module_info_get_predicate_table(Module, PredTable),
(
predicate_table_search_pred_m_n_a(PredTable,
unqualified("mercury_builtin"), PredName, Arity,
[PredId0])
->
PredId = PredId0
;
string__int_to_string(Arity, ArityS),
string__append_list(["can't locate mercury_builtin:", PredName,
"/", ArityS], ErrorMessage),
error(ErrorMessage)
),
module_info_pred_info(Module, PredId, PredInfo),
(
pred_info_procids(PredInfo, [ProcId0])
->
ProcId = ProcId0
;
string__int_to_string(Arity, ArityS),
string__append_list(["too many modes for pred mercury_builtin:",
PredName, "/", ArityS], ErrorMessage),
error(ErrorMessage)
),
Call = call(PredId, ProcId, Args, not_builtin, no, qualified(
unqualified("mercury_builtin"), PredName)),
set__init(NonLocals0),
set__insert_list(NonLocals0, Args, NonLocals),
(
(
Detism = failure
;
Detism = erroneous
)
->
instmap_delta_init_unreachable(InstMapDelta)
;
instmap_delta_from_assoc_list(InstMap, InstMapDelta)
),
goal_info_init(NonLocals, InstMapDelta, Detism, GoalInfo0),
goal_info_add_feature(GoalInfo0, Feature, GoalInfo),
Goal = Call - GoalInfo.
:- pred gen_int_construction(string, int, map(var, type), map(var, type),
varset, varset, var, hlds_goal).
:- mode gen_int_construction(in, in, in, out, in, out, out, out) is det.
gen_int_construction(VarName, VarValue, VarTypes0, VarTypes, VarSet0, VarSet,
Var, Goal) :-
varset__new_named_var(VarSet0, VarName, Var, VarSet),
term__context_init(Context),
VarType = term__functor(term__atom("int"), [], Context),
map__set(VarTypes0, Var, VarType, VarTypes),
Inst = bound(unique, [functor(int_const(VarValue), [])]),
VarUnify = unify(Var, functor(int_const(VarValue), []),
(free -> Inst) - (Inst -> Inst),
construct(Var, int_const(VarValue), [], []),
unify_context(explicit, [])),
set__singleton_set(VarNonLocals, Var),
instmap_delta_from_assoc_list([Var - Inst],
VarInstMapDelta),
goal_info_init(VarNonLocals, VarInstMapDelta, det,
VarGoalInfo),
Goal = VarUnify - VarGoalInfo.
:- pred get_table_var_type(type).
:- mode get_table_var_type(out) is det.
get_table_var_type(Type) :-
construct_type(qualified(unqualified("mercury_builtin"),
"c_pointer") - 0, [], Type).
:- pred get_input_output_vars(list(var), list(mode), module_info, list(var),
list(var)).
:- mode get_input_output_vars(in, in, in, out, out) is det.
get_input_output_vars([], [], _, [], []).
get_input_output_vars([_|_], [], _, _, _) :-
error("get_input_output_vars: lists not same length").
get_input_output_vars([], [_|_], _, _, _) :-
error("get_input_output_vars: lists not same length").
get_input_output_vars([Var|RestV], [Mode|RestM], Module, InVars, OutVars) :-
(
mode_is_fully_input(Module, Mode)
->
get_input_output_vars(RestV, RestM, Module, InVars0, OutVars),
InVars = [Var|InVars0]
;
mode_is_fully_output(Module, Mode)
->
get_input_output_vars(RestV, RestM, Module, InVars, OutVars0),
OutVars = [Var|OutVars0]
;
error(
"Only fully input/output arguments are allowed in tabled code!")
).
:- pred create_instmap_delta(hlds_goals, instmap_delta).
:- mode create_instmap_delta(in, out) is det.
create_instmap_delta([], IMD) :-
instmap_delta_from_assoc_list([], IMD).
create_instmap_delta([Goal|Rest], IMD) :-
Goal = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, IMD0),
create_instmap_delta(Rest, IMD1),
instmap_delta_apply_instmap_delta(IMD0, IMD1, IMD).
:- pred builtin_type_to_string(builtin_type, string).
:- mode builtin_type_to_string(in, out) is det.
builtin_type_to_string(int_type, "int").
builtin_type_to_string(char_type, "char").
builtin_type_to_string(str_type, "string").
builtin_type_to_string(float_type, "float").
builtin_type_to_string(pred_type, "pred").
builtin_type_to_string(enum_type, "enum").
builtin_type_to_string(polymorphic_type, "any").
builtin_type_to_string(user_type, "any").
New File: runtime/mercury_table_any.c
===================================================================
/*
** Copyright (C) 1997 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** This module defines the mercury_table_type() function.
*/
#include "mercury_imp.h"
#include "mercury_tabling.h"
#include "mercury_table_any.h"
#include "mercury_type_info.h"
#include <stdio.h>
/*
** Prototypes.
*/
static Word get_base_type_layout_entry(Word data, Word *type_info);
static Word * make_type_info(Word *term_type_info, Word *arg_pseudo_type_info,
bool *allocated);
MR_DECLARE_STRUCT(mercury_data___base_type_info_pred_0);
MR_DECLARE_STRUCT(mercury_data___base_type_info_func_0);
/*
** Due to the depth of the control here, we'll use 4 space indentation.
**
** NOTE : changes to this function will probably also have to be reflected
** in mercury_deep_copy.c and std_util::ML_expand().
*/
Word **
MR_table_type(Word *type_info, Word data, Word** Table)
{
Word layout_entry, *entry_value, *data_value;
int data_tag, entry_tag;
int arity, i;
bool allocated;
Word *argument_vector, *type_info_vector, *new_type_info;
Word new_data;
data_tag = tag(data);
data_value = (Word *) body(data, data_tag);
layout_entry = get_base_type_layout_entry(data_tag, type_info);
entry_tag = tag(layout_entry);
entry_value = (Word *) body(layout_entry, entry_tag);
switch(entry_tag) {
case TYPELAYOUT_CONST_TAG: /* and COMP_CONST_TAG */
/* Some builtins need special treatment */
if ((Word) entry_value <= TYPELAYOUT_MAX_VARINT) {
int builtin_type = unmkbody(entry_value);
switch(builtin_type) {
case TYPELAYOUT_UNASSIGNED_VALUE:
fatal_error("Attempt to use an UNASSIGNED tag "
"in table_any");
break;
case TYPELAYOUT_UNUSED_VALUE:
fatal_error("Attempt to use an UNUSED tag "
"in table_any");
break;
case TYPELAYOUT_STRING_VALUE:
Table = (Word**) MR_TABLE_STRING(Table, data);
break;
case TYPELAYOUT_FLOAT_VALUE:
Table = (Word**) MR_TABLE_FLOAT(Table, data);
break;
case TYPELAYOUT_INT_VALUE:
Table = (Word**) MR_TABLE_INT(Table, data);
break;
case TYPELAYOUT_CHARACTER_VALUE:
Table = (Word**) MR_TABLE_CHAR(Table, data);
break;
case TYPELAYOUT_UNIV_VALUE:
{
Table = (Word**) MR_TABLE_TYPE_INFO(Table,
data_value[UNIV_OFFSET_FOR_TYPEINFO]);
Table = (Word**) MR_TABLE_ANY(Table,
data_value[UNIV_OFFSET_FOR_TYPEINFO],
data_value[UNIV_OFFSET_FOR_DATA]);
break;
}
case TYPELAYOUT_PREDICATE_VALUE:
{
Word args = data_value[0];
Table = (Word **) MR_TABLE_WORD(Table, args);
Table = (Word **) MR_TABLE_WORD(Table, data_value[1]);
for (i = 0; i < args; i++) {
Table = (Word **) MR_TABLE_ANY(Table,
(Word *) type_info[i +
TYPEINFO_OFFSET_FOR_PRED_ARGS],
data_value[i+2]);
}
}
case TYPELAYOUT_VOID_VALUE:
fatal_error("Attempt to use a VOID tag in table_any");
break;
case TYPELAYOUT_ARRAY_VALUE:
Table = (Word**) MR_TABLE_ARRAY(Table, data);
break;
case TYPELAYOUT_TYPEINFO_VALUE:
Table = (Word**) MR_TABLE_TYPE_INFO(Table, data_value);
break;
case TYPELAYOUT_C_POINTER_VALUE:
fatal_error("Attempt to use a C_POINTER tag "
"in table");
break;
default:
fatal_error("Invalid tag value in table_any");
break;
}
} else {
if (MR_TYPELAYOUT_ENUM_VECTOR_IS_ENUM(entry_value)) {
Word functors =
MR_TYPELAYOUT_ENUM_VECTOR_NUM_FUNCTORS(entry_value);
Table = (Word**) MR_TABLE_ENUM(Table, functors, data);
} else {
Word functors =
MR_TYPELAYOUT_ENUM_VECTOR_NUM_FUNCTORS(entry_value);
Table = (Word**) MR_TABLE_TAG(Table, data_tag);
Table = (Word**) MR_TABLE_ENUM(Table, functors,
(Word)data_value);
}
}
break;
case TYPELAYOUT_SIMPLE_TAG:
argument_vector = data_value;
arity = entry_value[TYPELAYOUT_SIMPLE_ARITY_OFFSET];
type_info_vector = entry_value + TYPELAYOUT_SIMPLE_ARGS_OFFSET;
Table = (Word**) MR_TABLE_TAG(Table, data_tag);
/* copy arguments */
for (i = 0; i < arity; i++) {
new_type_info = make_type_info(type_info,
(Word *) type_info_vector[i], &allocated);
Table = (Word**) MR_TABLE_ANY(Table, new_type_info,
argument_vector[i]);
if (allocated) {
table_free(new_type_info);
}
}
break;
case TYPELAYOUT_COMPLICATED_TAG:
{
Word secondary_tag;
Word num_sharers;
Word *new_entry;
secondary_tag = *data_value;
argument_vector = data_value + 1;
new_entry = (Word *) entry_value[secondary_tag +1];
arity = new_entry[TYPELAYOUT_SIMPLE_ARITY_OFFSET];
type_info_vector = new_entry +
TYPELAYOUT_SIMPLE_ARGS_OFFSET;
Table = (Word**) MR_TABLE_TAG(Table, data_tag);
num_sharers = MR_TYPELAYOUT_COMPLICATED_VECTOR_NUM_SHARERS(
entry_value);
Table = (Word**) MR_TABLE_ENUM(Table, num_sharers, secondary_tag);
for (i = 0; i < arity; i++) {
new_type_info = make_type_info(type_info,
(Word *) type_info_vector[i], &allocated);
Table = (Word**) MR_TABLE_ANY(Table, new_type_info,
argument_vector[i]);
if (allocated) {
table_free(new_type_info);
}
}
break;
}
case TYPELAYOUT_EQUIV_TAG:
/* note: we treat no_tag types just like equivalences */
if ((Word) entry_value < TYPELAYOUT_MAX_VARINT) {
Table = (Word**) MR_TABLE_ANY(Table,
(Word *) type_info[(Word) entry_value], data);
} else {
/*
** offset 0 is no-tag indicator
** offset 1 is the pseudo-typeinfo
** (as per comments in base_type_layout.m)
** XXX should avoid use of hard-coded offset `1' here
*/
new_type_info = make_type_info(type_info,
(Word *) entry_value[1], &allocated);
Table = (Word**) MR_TABLE_ANY(Table, new_type_info, data);
if (allocated) {
table_free(new_type_info);
}
}
break;
default:
fatal_error("Unknown layout tag in table_any");
break;
}
return Table;
} /* end table_any() */
static Word
get_base_type_layout_entry(Word data_tag, Word *type_info)
{
Word *base_type_info, *base_type_layout;
base_type_info = (Word *) type_info[0];
if (base_type_info == 0) {
base_type_info = type_info;
}
base_type_layout = (Word *) base_type_info[OFFSET_FOR_BASE_TYPE_LAYOUT];
return base_type_layout[data_tag];
}
/*
** Given a type_info (term_type_info) which contains a
** base_type_info pointer and possibly other type_infos
** giving the values of the type parameters of this type,
** and a pseudo-type_info (arg_pseudo_type_info), which contains a
** base_type_info pointer and possibly other type_infos
** giving EITHER
** - the values of the type parameters of this type,
** or - an indication of the type parameter of the
** term_type_info that should be substituted here
**
** This returns a fully instantiated type_info, a version of the
** arg_pseudo_type_info with all the type variables filled in.
** If there are no type variables to fill in, we return the
** arg_pseudo_type_info, unchanged. Otherwise, we allocate
** memory using malloc(). If memory is allocated, the boolean
** argument (passed by reference) is set to TRUE, otherwise it is
** set to FALSE. It is the caller's responsibility to check whether
** the call to make_type_info allocated memory, and if so, free
** it.
**
** This code could be tighter. In general, we want to
** handle our own allocations rather than using malloc().
** Also, we might be able to do only one traversal.
**
** NOTE: If you are changing this code, you might also need
** to change the code in create_type_info in library/std_util.m,
** which does much the same thing, only allocating on the
** heap instead of using malloc.
*/
static Word *
make_type_info(Word *term_type_info, Word *arg_pseudo_type_info,
bool *allocated)
{
int arity, i, extra_args;
Word *base_type_info;
Word *type_info;
*allocated = FALSE;
/*
** The arg_pseudo_type_info might be a polymorphic variable,
** is so - substitute.
*/
if (TYPEINFO_IS_VARIABLE(arg_pseudo_type_info)) {
return (Word *) term_type_info[(Word) arg_pseudo_type_info];
}
base_type_info = MR_TYPEINFO_GET_BASE_TYPEINFO(arg_pseudo_type_info);
/* no arguments - optimise common case */
if (base_type_info == arg_pseudo_type_info) {
return arg_pseudo_type_info;
}
if (MR_BASE_TYPEINFO_IS_HO(base_type_info)) {
arity = MR_TYPEINFO_GET_HIGHER_ARITY(arg_pseudo_type_info);
extra_args = 2;
} else {
arity = MR_BASE_TYPEINFO_GET_TYPE_ARITY(base_type_info);
extra_args = 1;
}
/*
** Check for type variables -- if there are none,
** we don't need to create a new type_info.
*/
for (i = arity + extra_args - 1; i >= extra_args; i--) {
if (TYPEINFO_IS_VARIABLE(arg_pseudo_type_info[i])) {
break;
}
}
/*
** Do we need to create a new type_info?
*/
if (i >= extra_args) {
type_info = table_allocate((arity + extra_args) * sizeof(Word));
*allocated = TRUE;
/*
** Copy any preliminary arguments to the type_info
** (this means the base_type_info and possibly
** arity for higher order terms).
*/
for (i = 0; i < extra_args; i++) {
type_info[i] = arg_pseudo_type_info[i];
}
/*
** Copy type arguments, substituting for any
** type variables.
*/
for (i = extra_args; i < arity + extra_args; i++) {
if (TYPEINFO_IS_VARIABLE(arg_pseudo_type_info[i])) {
type_info[i] = term_type_info[
arg_pseudo_type_info[i]];
if (type_info[i] < TYPELAYOUT_MAX_VARINT) {
fatal_error("make_type_info: "
"unbound type variable.");
}
} else {
type_info[i] = arg_pseudo_type_info[i];
}
}
return type_info;
} else {
return arg_pseudo_type_info;
}
} /* end make_type_info() */
New File: runtime/mercury_table_any.h
===================================================================
#ifndef _MERCURY_TABLE_ANY_H
#define _MERCURY_TABLE_ANY_H
/*
** This function will lookup or insert any type of value into a
** table. It uses the provided type_info to extract the necessary
** info to do this.
*/
Word ** MR_table_type(Word *type_info, Word data_value,
Word ** Table);
#endif /* not _MERCURY_TABLE_ANY_H */
New File: runtime/mercury_table_enum.c
===================================================================
/*
** Copyright (C) 1998 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** This module defines the MR_int_index_lookup_or_add() function.
*/
#include "mercury_imp.h"
#define ELEMENT(Table, Key) ((Word**)&(Table[Key]))
/*
** MR_int_index_lookup_or_add() : This function maintains a simple indexed
** table of size Range.
*/
Word **
MR_int_index_lookup_or_add(Word ** T, Integer Key,
Integer Range)
{
Word *Table = *T; /* Deref table */
if (Table == NULL) {
*T = Table = table_allocate(sizeof(Word*)*Range);
memset(Table, 0, sizeof(Word*)*Range);
}
return ELEMENT(Table, Key);
}
New File: runtime/mercury_table_enum.h
===================================================================
#ifndef _MERCURY_TABLE_ENUM_H
#define _MERCURY_TABLE_ENUM_H
/*
** MR_int_index_lookup_or_add() : This function maintains a simple indexed
** table of size Range.
*/
Word ** MR_int_index_lookup_or_add(Word **, Integer, Integer);
#endif /* not _MERCURY_TABLE_ENUM_H */
New File: runtime/mercury_table_int_float_string.c
===================================================================
/*
** Copyright (C) 1998 the University of Melbourne.
** this file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** this module defines the int_hash_lookup_or_add(), float_hash_lookup_or_add()
** and string_hash_lookup_or_add() function.
*/
#include "mercury_imp.h"
/* Initial size of a new table */
#define TABLE_START_SIZE primes[0]
/* Amount the table is allowed to fill. Must be less than 0.9 if you want
even poor lookup times */
#define MAX_EL_SIZE_RATIO 0.95
/* Extract info from a table */
#define SIZE(table) (((TableRoot *) table)->size)
#define ELEMENTS(table) (((TableRoot *) table)->used_elements)
#define BUCKET(table, Bucket) ((TableNode **) &(((TableRoot *) table)-> \
elements))[(Bucket)]
typedef struct {
Word key;
Word * data;
} TableNode;
typedef struct {
Word size;
Word used_elements;
Word elements;
} TableRoot;
static Word next_prime(Word);
static Word * create_hash_table(Word);
static void re_hash(Word *, Word, TableNode * Node);
/*
* Prime numbers which are close to powers of 2. Used for choosing
* the next size for a hash table.
*/
#define NUM_OF_PRIMES 16
static Word primes[NUM_OF_PRIMES] =
{127, 257, 509, 1021, 2053, 4099, 8191, 16381, 32771, 65537, 131071,
262147, 524287, 1048573, 2097143, 4194301};
/*
* Return the next prime number greater than the number received.
* If no such prime number can be found, compute an approximate one.
*/
static Word
next_prime(Word old_size)
{
int i;
i = 0;
while ( (old_size >= primes[i]) && (i < NUM_OF_PRIMES) ) {
i++;
}
if (i < NUM_OF_PRIMES) {
return (primes[i]);
} else {
return (2 * old_size - 1);
}
}
/* Create a new empty hash table */
static Word *
create_hash_table(Word table_size)
{
Word i;
TableRoot * table =
table_allocate(sizeof(Word) * 2 + table_size *
sizeof(TableNode *));
table->size = table_size;
table->used_elements = 0;
for (i=0; i<table_size; i++) {
BUCKET(table, i) = NULL;
}
return (Word *) table;
}
/* Insert key and Data into a new hash table using the given hash.
* this function does not have to do compares as the given key
* is definitely not in the table.
*/
static void
re_hash(Word * table, Word hash, TableNode * node)
{
Word bucket = hash % SIZE(table);
while (BUCKET(table, bucket)) {
++bucket;
if (bucket == SIZE(table))
bucket = 0;
}
BUCKET(table, bucket) = node;
++ELEMENTS(table);
}
/* Look to see if the given integer key is in the given table. If it
** is return the address of the data pointer associated with the key.
** If it is not; create a new element for the key in the table and
** return the address of its data pointer
**/
Word **
MR_int_hash_lookup_or_add(Word ** t, Integer key)
{
TableNode * p, * q;
Word * table = *t; /* Deref the table pointer */
Word bucket;
/* Has the the table been built? */
if (table == NULL) {
table = create_hash_table(TABLE_START_SIZE);
*t = table;
}
bucket = key % SIZE(table);
p = BUCKET(table, bucket);
/* Find if the element is present. If not add it */
while (p) {
if (key == p->key) {
return &p->data;
}
if (bucket == SIZE(table))
bucket = 0;
p = BUCKET(table, bucket);
}
p = table_allocate(sizeof(TableNode));
p->key = key;
p->data = NULL;
/* Rehash the table if it has grown to full */
if ((float) ELEMENTS(table) / (float) SIZE(table) >
MAX_EL_SIZE_RATIO)
{
int old_size = SIZE(table);
int new_size = next_prime(old_size);
Word * new_table = create_hash_table(new_size);
int i;
for (i = 0; i < old_size; i++) {
q = BUCKET(table, i);
if (q) {
re_hash(new_table, q->key, q);
}
}
/* Free the old table */
table_free(table);
/* Point to the new table */
*t = new_table;
/* Add a new element */
re_hash(new_table, key, p);
} else {
BUCKET(table, bucket) = p;
++ELEMENTS(table);
}
return &p->data;
}
/* Look to see if the given float key is in the given table. If it
** is return the address of the data pointer associated with the key.
** If it is not create a new element for the key in the table and
** return the address of its data pointer
**/
Word **
MR_float_hash_lookup_or_add(Word ** t, Float key)
{
TableNode * p, * q;
Word * table = *t; /* Deref the table pointer */
Word bucket;
Word hash;
/* Has the the table been built? */
if (table == NULL) {
table = create_hash_table(TABLE_START_SIZE);
*t = table;
}
hash = hash_float(key);
bucket = hash % SIZE(table);
p = BUCKET(table, bucket);
/* Find if the element is present. If not add it */
while (p) {
if (key == word_to_float(p->key)) {
return &p->data;
}
++bucket;
if (bucket == SIZE(table))
bucket = 0;
p = BUCKET(table, bucket);
}
p = table_allocate(sizeof(TableNode));
p->key = float_to_word(key);
p->data = NULL;
/* Rehash the table if it has grown to full */
if ((float) ELEMENTS(table) / (float) SIZE(table) >
MAX_EL_SIZE_RATIO)
{
int old_size = SIZE(table);
int new_size = next_prime(old_size);
Word * new_table = create_hash_table(new_size);
int i;
for (i = 0; i < old_size; i++) {
q = BUCKET(table, i);
if (q) {
re_hash(new_table, hash_float(q->key), q);
}
}
/* Free the old table */
table_free(table);
/* Point to the new table */
*t = new_table;
/* Add a new element */
re_hash(new_table, hash, p);
} else {
++ELEMENTS(table);
BUCKET(table, bucket) = p;
}
return &p->data;
}
/* Look to see if the given string key is in the given table. If it
** is return the address of the data pointer associated with the key.
** If it is not create a new element for the key in the table and
** return the address of its data pointer
**/
Word **
MR_string_hash_lookup_or_add(Word ** t, String key)
{
TableNode * p, * q;
Word * table = *t; /* Deref the table pointer */
Word bucket;
Word hash;
/* Has the the table been built? */
if (table == NULL) {
table = create_hash_table(TABLE_START_SIZE);
*t = table;
}
hash = hash_string(key);
bucket = hash % SIZE(table);
p = BUCKET(table, bucket);
/* Find if the element is present. */
while (p) {
int res = strtest((String)p->key, key);
if (res == 0) {
return &p->data;
}
++bucket;
if (bucket == SIZE(table))
bucket = 0;
p = BUCKET(table, bucket);
}
p = table_allocate(sizeof(TableNode));
p->key = (Word) key;
p->data = NULL;
/* Rehash the table if it has grown to full */
if ((float) ELEMENTS(table) / (float) SIZE(table) >
MAX_EL_SIZE_RATIO)
{
int old_size = SIZE(table);
int new_size = next_prime(old_size);
Word * new_table = create_hash_table(new_size);
int i;
for (i = 0; i < old_size; i++) {
q = BUCKET(table, i);
if (q) {
re_hash(new_table, hash_string(q->key), q);
}
}
/* Free the old table */
table_free(t);
/* Point to the new table */
*t = new_table;
/* Add a new element to rehashed table */
re_hash(new_table, hash, p);
} else {
BUCKET(table, bucket) = p;
++ELEMENTS(table);
}
return &p->data;
}
New File: runtime/mercury_table_int_float_string.h
===================================================================
#ifndef _MERCURY_INT_FLOAT_STRING_H
#define _MERCURY_INT_FLOAT_STRING_H
/* Look to see if the given integer key is in the given table. If it
** is return the address of the data pointer associated with the key.
** If it is not; create a new element for the key in the table and
** return the address of its data pointer
**/
Word ** MR_int_hash_lookup_or_add(Word ** Table, Integer Key);
/* Look to see if the given float key is in the given table. If it
** is return the address of the data pointer associated with the key.
** If it is not create a new element for the key in the table and
** return the address of its data pointer
**/
Word ** MR_float_hash_lookup_or_add(Word ** Table, Float Key);
/* Look to see if the given string key is in the given table. If it
** is return the address of the data pointer associated with the key.
** If it is not create a new element for the key in the table and
** return the address of its data pointer
**/
Word ** MR_string_hash_lookup_or_add(Word ** Table, String Key);
#endif /* not _MERCURY_INT_FLOAT_STRING_H */
New File: runtime/mercury_table_type_info.c
===================================================================
/*
** Copyright (C) 1997 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** This module defines the type_info_lookup_or_add() function.
*/
#include "mercury_imp.h"
#include "mercury_table_type_info.h"
typedef struct _tree_node {
Word * key;
Word value;
struct _tree_node * right;
struct _tree_node * left;
} TreeNode;
Word **
MR_type_info_lookup_or_add(Word ** table, Word * type_info)
{
TreeNode *p, *q;
int i;
if (*table == NULL) {
p = table_allocate(sizeof(TreeNode));
p->key = type_info;
p->value = (Word) NULL;
p->left = NULL;
p->right = NULL;
*table = (Word *) p;
return (Word**) &p->value;
}
p = (TreeNode*) *table;
while (p != NULL) {
i = MR_compare_type_info((Word) p->key, (Word) type_info);
if (i == COMPARE_EQUAL) {
return (Word**) &p->value;
}
q = p;
if (i == COMPARE_LESS) {
p = p->left;
} else {
p = p->right;
}
}
p = table_allocate(sizeof(TreeNode));
p->key = type_info;
p->value = (Word) NULL;
p->left = NULL;
p->right = NULL;
if (i == COMPARE_LESS) {
q->left = p;
} else {
q ->right = p;
}
return (Word**) &p->value;
}
New File: runtime/mercury_table_type_info.h
===================================================================
#ifndef _MERCURY_TABLE_TYPE_INFO
#define _MERCURY_TABLE_TYPE_INFO
Word ** MR_type_info_lookup_or_add(Word **, Word *);
#endif /* not _MERCURY_TABLE_TYPE_INFO */
New File: runtime/mercury_tabling.h
===================================================================
/*
** Copyright (C) 1995-1997 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** mercury_tabling.h - definitions of some basic macros used by the tabling
** code generated by the Mercury compiler and by the Mercury runtime.
*/
#ifndef _MERCURY_TABLING_H
#define _MERCURY_TABLING_H
#include "mercury_table_enum.h"
#include "mercury_table_any.h"
#include "mercury_table_type_info.h"
#include "mercury_table_int_float_string.h"
#define MR_TABLE_DEBUG
#define MR_TABLE_WORD(Table, Value) \
(Word) MR_int_hash_lookup_or_add(Table, (Integer)Value);
#define MR_TABLE_INT(Table, Value) \
(Word) MR_int_hash_lookup_or_add(Table, Value);
#define MR_TABLE_FLOAT(Table, Value) \
(Word) MR_float_hash_lookup_or_add(Table, Value);
#define MR_TABLE_CHAR(Table, Value) \
(Word) MR_int_hash_lookup_or_add(Table, (Integer)Value);
#define MR_TABLE_STRING(Table, Value) \
(Word) MR_string_hash_lookup_or_add(Table, (String)Value);
#define MR_TABLE_ENUM(Table, Range, Value) \
(Word) MR_int_index_lookup_or_add(Table, Value, Range)
#define MR_TABLE_ARRAY(Table, Array) \
(Word**)0;fatal_error("Tabling of arrays not yet supported")
#define MR_TABLE_TAG(Table, Tag) \
(Word) MR_int_index_lookup_or_add(Table, Tag, 1 << TAGBITS)
#define MR_TABLE_TYPE_INFO(Table, Type) \
(Word) MR_type_info_lookup_or_add(Table, (Word*) Type)
#define MR_TABLE_ANY(Table, TypeInfo, Value) \
(Word) MR_table_type((Word*)TypeInfo, Value, (Word**)Table)
#define MR_TABLE_CREATE_ANSWER_BLOCK(AnswerBlock, Elements) \
do { \
*((Word**)AnswerBlock) = \
table_allocate(sizeof(Word)*Elements); \
} while(0)
#define MR_TABLE_GET_ANSWER(Offset, AnswerBlock) \
(*((Word**)AnswerBlock))[Offset]
#ifdef CONSERVATIVE_GC
#define MR_TABLE_SAVE_ANSWER(Offset, AnswerBlock, Value, TypeInfo) \
do { \
(*((Word**)AnswerBlock))[Offset] = Value; \
} while(0)
#else /* not CONSERVATIVE_GC */
#define MR_TABLE_SAVE_ANSWER(Offset, AnswerBlock, Value, TypeInfo) \
do { \
(*((Word**)AnswerBlock))[Offset] = \
deep_copy(Value, &TypeInfo, NULL, NULL); \
restore_transient_registers(); \
} while(0)
#endif /* CONSERVATIVE_GC */
#ifdef CONSERVATIVE_GC
#define table_allocate(Size) \
GC_malloc(Size);
#define table_reallocate(Pointer, Size) \
GC_realloc(Pointer, Size);
#define table_free(Pointer) \
GC_free(Pointer);
#else /* not CONSERVATIVE_GC */
#define table_allocate(Size) \
0;fatal_error("tabling only supported in conservative gc grades")
#define table_reallocate(Pointer, Size) \
0;fatal_error("tabling only supported in conservative gc grades")
#define table_free(Pointer) \
fatal_error("tabling only supported in conservative gc grades")
#endif /* CONSERVATIVE_GC */
#define table_copy_mem(Dest, Source, Size) \
memcpy(Dest, Source, Size);
#ifdef MR_TABLE_DEBUG
#include <stdio.h>
#include <varargs.h>
static void table_printf(const char*, ...);
static void table_printf(const char *A, ...)
{
va_list list;
va_start(list);
vprintf(A, list);
}
#else /* not MR_TABLE_DEBUG */
static void table_printf(const char*, ...);
static void table_printf(const char *A, ...)
{
}
#endif /* not MR_TABLE_DEBUG */
#endif /* not MERCURY_TABLING_H */
More information about the developers
mailing list