[m-dev.] Tabling [3/3]
Fergus Henderson
fjh at cs.mu.OZ.AU
Tue Mar 10 03:24:24 AEDT 1998
On 09-Mar-1998, Oliver Hutchison <ohutch at students.cs.mu.oz.au> wrote:
> New File: compiler/table_gen.m
> % Copyright (C) 1996-1998
Has it really been that long? ;-)
> % 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("
> % static Word Table = 0;
> % T0 = &Table;
> % "),
`T0' here is an undeclared variable.
> 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)
> ;
> error(
> "table_gen__process_proc: unsupported code model for tabled pred/func")
> ),
Better to use a switch rather than an if-then-else.
Then there's no need for the call to error/1.
> %
> % Transform deteministic procedures.
> %
> :- pred table_gen__create_new_det_goal(eval_method, hlds_goal, module_info,
s/deteministic/deterministic/
If recent experience is anything to go on,
that word sure is hard to spell ;-)
> table_gen__create_new_non_goal(EvalMethod, OrigGoal, Module, HeadVars,
> HeadVarModes, VarTypes0, VarTypes, VarSet0, VarSet, Goal) :-
> map__init(StoreMap),
> (
> EvalMethod = eval_memo
> ->
> WorkingOnAnsGoal = SuspendGoal
> ;
> EvalMethod = eval_minimal
> ->
> WorkingOnAnsGoal = FailGoal
> ;
> error(
> "table_gen__create_new_non_goal: unsupported evaluation model")
> ),
Why isn't eval_loopcheck supported here?
> generate_get_table_goals(VarTypes0, VarTypes, VarSet0, VarSet, Module,
> TableVar, Goal) :-
> generate_new_table_var(VarTypes0, VarTypes, VarSet0, VarSet,
> TableVar),
>
> module_info_get_predicate_table(Module, PredTable),
> (
> predicate_table_search_pred_m_n_a(PredTable,
> "mercury_builtin", "get_table", 1, [PredId0])
This will need to change when you merge in my recent changes...
> error(
> "to many modes for predicate mercury_builtin:get_table/1")
s/to/too/
> GoalEx = pragma_c_code(will_not_call_mercury, PredId, ProcId,
> [TableVar], [yes("TableVar" - TableVarMode)],
> [TableVarType], ordinary(
> " {
> static Word Table = 0;
> TableVar = (Word)&Table;
> }
> ",
> no)),
Declaring a static variable inside the code for a
`pragma c_code' predicate is dangerous.
At very least you need to mark the predicate with
`pragma no_inline'.
> gen_lookup_call_for_type(TypeCat, Type, TableVar, ArgVar, Module, VarTypes0,
> VarTypes, VarSet0, VarSet, NextTableVar, Goal) :-
> (
> TypeCat = pred_type
> ->
> error("gen_lookup_call_for_type: pred types not supported")
Hmm, ideally this should be checked for at an earlier stage,
with an appropriate error message issued. Is it?
You should include a test case for this in tests/invalid.
...
> error(
> "gen_lookup_call_for_type: unsuported type in tabled predicte/function")
s/unsuported/unsupported/
s/predicte/predicate/
> New File: runtime/mercury_table_any.c
The code here seems to be very similar to the code for something
else (ML_expand(), I think). You should put comments in both
places saying that if you modify one then you may need to modify
the other.
> 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);
... [200 lines later] ...
> Word
> get_base_type_layout_entry(Word data_tag, Word *type_info)
...
> Word *
> make_type_info(Word *term_type_info, Word *arg_pseudo_type_info,
> bool *allocated)
It would be helpful to the reader to include `static' on the
definitions, not just the declarations.
But actually, aren't those routines exactly the same as the ones
of the same name somewhere else? If so, you should make them
`extern' rather than `static' and just define them in only one place.
> New File: runtime/mercury_table_any.h
> ===================================================================
> #ifndef _MERCURY_TABLE_ANY_H
> #define _MERCURY_TABLE_ANY_H
>
> Word ** mercury_table_type(Word *type_info, Word data_value,
> Word ** Table);
The usual prefix for things in the runtime is `MR_', not `mercury_'.
The header file should document what the function does.
> New File: runtime/mercury_table_enum.h
> ===================================================================
> #ifndef _MERCURY_TABLE_ENUM_H
> #define _MERCURY_TABLE_ENUM_H
>
> Word ** int_index_lookup_or_add(Word **, Integer, Integer);
Needs an MR_ prefix, and should be documented.
> typedef struct {
> Word Key;
> Word * Data;
> } TableNode;
>
> typedef struct {
> Word Size;
> Word UsedElements;
> Word Elements;
> } TableRoot;
Struct fields should be lower-case.
> 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};
This list should probably be a little bit longer.
It's possible that someone might want a table bigger than 42M entries.
I suggest you go up to 4G.
Uh, never mind -- I see that you do something reasonable even if you
get past the end of the table.
> /* Create a new empty hash table */
> static Word *
> create_hash_table(Word TableSize)
Function arguments should be lower-case.
> {
> Word i;
> TableRoot * Table =
> table_allocate(sizeof(Word)*2+TableSize*sizeof(TableNode *));
Some whitespace between operators please:
s/*/ * /
s/+/ + /
> /* Rehash the table if it has grown to full */
> if ((float)ELEMENTS(Table) / (float)SIZE(Table) > MAX_EL_SIZE_RATIO) {
s/(float)/(float) /g
> /* Rehash the table if it has grown to full */
> if ((float)ELEMENTS(Table) / (float)SIZE(Table) > MAX_EL_SIZE_RATIO) {
Ditto.
I detect some duplicate code there around that part;
you should abstract it out into a subroutine.
> New File: runtime/mercury_table_int_float_string.h
> ===================================================================
> #ifndef _MERCURY_INT_FLOAT_STRING_H
> #define _MERCURY_INT_FLOAT_STRING_H
>
> Word ** int_hash_lookup_or_add(Word ** Table, Integer Key);
> Word ** float_hash_lookup_or_add(Word ** Table, Float Key);
> Word ** string_hash_lookup_or_add(Word ** Table, String Key);
Need MR_ prefixes and documentation.
> void
> table_dump_profile()
> {
s/()/(void)/
> printf(" Profilng stats for table operation\n");
>
> printf(" Number of calls to TableHasFailed = %d \n",
> (int) MR_Table_Prof_HasFailed_Call);
> printf(" Number of calls to TableCreateAnsBlock = %d \n",
> (int) MR_Table_Prof_CreateAnsBlock_Call);
> printf(" Number of calls to TableSaveIntAns = %d \n",
> (int) MR_Table_Prof_SaveIntAns_Call);
> printf(" Number of calls to TableSaveCharAns = %d \n",
> (int) MR_Table_Prof_SaveCharAns_Call);
> printf(" Number of calls to TableSaveStringAns = %d \n",
> (int) MR_Table_Prof_SaveStringAns_Call);
> printf(" Number of calls to TableSaveFloatAns = %d \n",
> (int) MR_Table_Prof_SaveFloatAns_Call);
> printf(" Number of calls to TableSaveAnyAns = %d \n",
> (int) MR_Table_Prof_SaveAnyAns_Call);
> printf(" Number of calls to TableSaveFailure = %d \n",
> (int) MR_Table_Prof_SaveFailure_Call);
> printf(" Number of calls to TableRestoreInt = %d \n",
> (int) MR_Table_Prof_RestoreInt_Call);
> printf(" Number of calls to TableRestoreChar = %d \n",
> (int) MR_Table_Prof_RestoreChar_Call);
> printf(" Number of calls to TableRestoreString = %d \n",
> (int) MR_Table_Prof_RestoreString_Call);
> printf(" Number of calls to TableRestoreFloat = %d \n",
> (int) MR_Table_Prof_RestoreFloat_Call);
> printf(" Number of calls to TableRestoreAny = %d \n",
> (int) MR_Table_Prof_RestoreAny_Call);
> printf(" Number of calls to TableSetup = %d \n",
> (int) MR_Table_Prof_Setup_Call);
> printf(" Number of calls to TableRetAllAns = %d \n",
> (int) MR_Table_Prof_RetAllAns_Call);
> printf(" Number of calls to TableGenAnsTable = %d \n",
> (int) MR_Table_Prof_GenAnsTable_Call);
> printf(" Number of calls to TableHaveAllAns = %d \n",
> (int) MR_Table_Prof_HaveAllAns_Call);
> printf(" Number of calls to TableHaveSomeAns = %d \n",
> (int) MR_Table_Prof_HaveSomeAns_Call);
> printf(" Number of calls to TableNewAns = %d \n",
> (int) MR_Table_Prof_NewAns_Call);
> printf(" Number of calls to TableMarkHaveAllAns = %d \n",
> (int) MR_Table_Prof_MarkHaveAllAns_Call);
> printf(" Number of calls to TableMarkHaveSomeAns = %d \n",
> (int) MR_Table_Prof_MarkHaveSomeAns_Call);
> printf(" Number of calls to TableMarkAsReturned = %d \n",
> (int) MR_Table_Prof_MarkAsReturned_Call);
> printf(" Number of calls to TableSuspend = %d \n",
> (int) MR_Table_Prof_Suspend_Call);
> printf(" Number of calls to TableResume = %d \n",
> (int) MR_Table_Prof_Resume_Call);
> printf(" Number of calls to TableNewAnsSlot = %d \n",
> (int) MR_Table_Prof_NewAnsSlot_Call);
> printf(" Number of calls to TableMemCpy = %d Bytes moved %d\n",
> (int) MR_Table_Prof_MemCpy_Call,
> (int) MR_Table_Prof_Moved_Mem);
> printf(" Number of calls to TableMalloc = %d Bytes allocated %d\n",
> (int) MR_Table_Prof_Malloc_Call,
> (int) MR_Table_Prof_Malloc_Mem);
> printf(" Number of calls to TableReallc = %d Bytes reallocated %d\n",
> (int) MR_Table_Prof_Reallc_Call,
> (int) MR_Table_Prof_Realloc_Mem);
> printf(" Number of calls to TableFree = %d \n",
> (int) MR_Table_Prof_Free_Call);
s/ \n/\n/g
> New File: runtime/mercury_table_profile.h
> ===================================================================
> #ifndef _MERCURY_TABLE_PROFILE
> #define _MERCURY_TABLE_PROFILE
>
> extern Word MR_Table_Prof_WorkingOnAns_Call;
> extern Word MR_Table_Prof_MarkWorkingOnAns_Call;
> extern Word MR_Table_Prof_LookupInsertInt_Call;
> extern Word MR_Table_Prof_LookupInsertChar_Call;
> extern Word MR_Table_Prof_LookupInsertString_Call;
> extern Word MR_Table_Prof_LookupInsertFloat_Call;
> extern Word MR_Table_Prof_LookupInsertEnum_Call;
> extern Word MR_Table_Prof_LookupInsertUser_Call;
> extern Word MR_Table_Prof_LookupInsertPoly_Call;
> extern Word MR_Table_Prof_HaveAns_Call;
> extern Word MR_Table_Prof_HasFailed_Call;
> extern Word MR_Table_Prof_CreateAnsBlock_Call;
> extern Word MR_Table_Prof_SaveIntAns_Call;
> extern Word MR_Table_Prof_SaveCharAns_Call;
> extern Word MR_Table_Prof_SaveStringAns_Call;
> extern Word MR_Table_Prof_SaveFloatAns_Call;
> extern Word MR_Table_Prof_SaveAnyAns_Call;
> extern Word MR_Table_Prof_SaveFailure_Call;
> extern Word MR_Table_Prof_RestoreInt_Call;
> extern Word MR_Table_Prof_RestoreChar_Call;
> extern Word MR_Table_Prof_RestoreString_Call;
> extern Word MR_Table_Prof_RestoreFloat_Call;
> extern Word MR_Table_Prof_RestoreAny_Call;
> extern Word MR_Table_Prof_Setup_Call;
> extern Word MR_Table_Prof_RetAllAns_Call;
> extern Word MR_Table_Prof_GenAnsTable_Call;
> extern Word MR_Table_Prof_HaveAllAns_Call;
> extern Word MR_Table_Prof_HaveSomeAns_Call;
> extern Word MR_Table_Prof_NewAns_Call;
> extern Word MR_Table_Prof_MarkHaveAllAns_Call;
> extern Word MR_Table_Prof_MarkHaveSomeAns_Call;
> extern Word MR_Table_Prof_MarkAsReturned_Call;
> extern Word MR_Table_Prof_Suspend_Call;
> extern Word MR_Table_Prof_Resume_Call;
> extern Word MR_Table_Prof_NewAnsSlot_Call;
> extern Word MR_Table_Prof_MemCpy_Call;
> extern Word MR_Table_Prof_Malloc_Call;
> extern Word MR_Table_Prof_Reallc_Call;
> extern Word MR_Table_Prof_Free_Call;
> extern Word MR_Table_Prof_Moved_Mem;
> extern Word MR_Table_Prof_Malloc_Mem;
> extern Word MR_Table_Prof_Realloc_Mem;
These should all be lower case (except for the MR_ prefix),
not mixed case.
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3 | -- the last words of T. S. Garp.
More information about the developers
mailing list