mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 06:14:59 +00:00
Estimated hours taken: 12
Branches: main
Add a new form of tabling pragma, fast_loose_memo. It differs from memo in
only one way: for arguments of user-defined types, instead of tabling every
single function symbol in the value, it tables a pointer to the term instead.
(Actually, it tables the contents of the selected argument register, so it
works even if the value is not a pointer.)
As the name implies, this form of tabling is faster than memo. The tradeoff
is that it is looser: if two invocations specify two terms that are at
different addresses but have the same value, this new form of tabling will
not recognize the commonality.
doc/reference_manual.texi:
Document the new pragma.
compiler/prog_data.m:
Generalize the type specifying eval methods to allow the expression
of the new form of tabling.
compiler/prog_io_pragma.m:
Parse the new form of tabling pragma.
compiler/hlds_pred.m:
Handle the new, more general form of memoing.
Add the required provisions for the representation of the new form
of trie step in tables.
compiler/table_gen.m:
Implement the new form of tabling as a minor variant of memo tabling.
Convert this module to four-space indentation to reduce the number
of bad line breaks.
compiler/layout_out.m:
compiler/prog_out.m:
Conform to the changes above.
library/table_builtins.m:
Add the primitives required to implement fast_loose_memo.
Fix an old bug: make table_lookup_insert_poly call the right macro.
runtime/mercury_tabling.h:
runtime/mercury_tabling_macros.h:
runtime/mercury_tabling_preds.h:
Provide the basic mechanism of fast_loose_memo tabling: a hash table
that works on MR_Words.
runtime/mercury_stack_layout.h:
Allow the representation of the new evaluation method and the new form
of trie step.
tests/tabling/fast_loose.{m,exp}:
Add this test case of the operation of fast_loose tabling. The test
case pronounces success only if fast_loose_memo is measured to be
significantly faster than plain memo.
tests/tabling/Mmakefile:
Enable the new test case.
460 lines
14 KiB
C
460 lines
14 KiB
C
/*
|
|
** Copyright (C) 1997-2000,2002-2005 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_macros.h
|
|
**
|
|
** This file defines macros used by the implementation of tabling
|
|
** (which means mostly the procedures defined in library/private_builtin.m).
|
|
** These macros just call the real implementation routines defined in
|
|
** runtime/mercury_tabling.c, but they also optionally print debugging
|
|
** information.
|
|
*/
|
|
|
|
#include "mercury_deep_copy.h" /* for MR_make_permanent */
|
|
|
|
#define MR_RAW_TABLE_ANY(table, type_info, value) \
|
|
MR_table_type((table), (type_info), (value))
|
|
|
|
#define MR_RAW_TABLE_ANY_FAST_LOOSE(table, type_info, value) \
|
|
MR_word_hash_lookup_or_add((table), (value))
|
|
|
|
#define MR_RAW_TABLE_TAG(table, tag) \
|
|
MR_int_fix_index_lookup_or_add((table), 1 << MR_TAGBITS, (tag))
|
|
|
|
#define MR_RAW_TABLE_ENUM(table, range, value) \
|
|
MR_int_fix_index_lookup_or_add((table), (range), (value))
|
|
|
|
#define MR_RAW_TABLE_START_INT(table, start, value) \
|
|
MR_int_start_index_lookup_or_add((table), (start), (value));
|
|
|
|
#define MR_RAW_TABLE_WORD(table, value) \
|
|
MR_int_hash_lookup_or_add((table), (value));
|
|
|
|
#define MR_RAW_TABLE_INT(table, value) \
|
|
MR_int_hash_lookup_or_add((table), (value));
|
|
|
|
#define MR_RAW_TABLE_CHAR(table, value) \
|
|
MR_int_hash_lookup_or_add((table), (value));
|
|
|
|
#define MR_RAW_TABLE_FLOAT(table, value) \
|
|
MR_float_hash_lookup_or_add((table), (value));
|
|
|
|
#define MR_RAW_TABLE_STRING(table, value) \
|
|
MR_string_hash_lookup_or_add((table), (value));
|
|
|
|
#define MR_RAW_TABLE_TYPEINFO(table, type_info) \
|
|
MR_type_info_lookup_or_add((table), (type_info))
|
|
|
|
#define MR_RAW_TABLE_TYPECLASSINFO(table, typeclass_info) \
|
|
MR_type_class_info_lookup_or_add((table), (typeclass_info))
|
|
|
|
#ifdef MR_TABLE_DEBUG
|
|
|
|
#define MR_DEBUG_NEW_TABLE_ANY(table, table0, type_info, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_ANY((table0), (type_info), \
|
|
(value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: any %x type %p => %p\n", \
|
|
(table0), (value), (type_info), (table));\
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_ANY(table, type_info, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_ANY((table), \
|
|
(type_info), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: any %x type %p => %p\n", \
|
|
prev_table, (value), (type_info), \
|
|
(table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_ANY_FAST_LOOSE(table, table0, type_info, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_ANY_FAST_LOOSE((table0), (type_info), \
|
|
(value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: any %x type %p => %p\n", \
|
|
(table0), (value), (type_info), (table));\
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_ANY_FAST_LOOSE(table, type_info, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_ANY_FAST_LOOSE((table), \
|
|
(type_info), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: any %x type %p => %p\n", \
|
|
prev_table, (value), (type_info), \
|
|
(table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_TAG(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_TAG((table0), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: tag %d => %p\n", \
|
|
(table0), (value), (table)) \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_TAG(table, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_TAG((table), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: tag %d => %p\n", \
|
|
prev_table, (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_ENUM(table, table0, count, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_ENUM((table0), (count), (value));\
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: enum %d of %d => %p\n", \
|
|
(table0), (value), (count), (table)); \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_ENUM(table, count, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_ENUM((table), (count), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: enum %d of %d => %p\n", \
|
|
prev_table, (value), (count), (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_START_INT(table, table0, start, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_START_INT((table0), (start), (value));\
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: int %d - %d => %p\n", \
|
|
(table0), (value), (start), (table)); \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_START_INT(table, start, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_START_INT((table), (start), (value));\
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: int %d - %d => %p\n", \
|
|
prev_table, (value), (start), (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_WORD(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_WORD((table0), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: word %d => %p\n", \
|
|
(table0), (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_WORD(table, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_WORD((table), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: word %d => %p\n", \
|
|
prev_table, (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_INT(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_INT((table0), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: int %d => %p\n", \
|
|
(table0), (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_INT(table, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_INT((table), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: int %d => %p\n", \
|
|
prev_table, (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_CHAR(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_CHAR((table0), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: char `%c'/%d => %p\n", \
|
|
(table0), (int) (value), \
|
|
(int) (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_CHAR(table, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_CHAR((table), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: char `%c'/%d => %p\n", \
|
|
prev_table, (int) (value), \
|
|
(int) (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_FLOAT(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_FLOAT((table0), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: float %f => %p\n", \
|
|
(table0), (double) (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_FLOAT(table, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_FLOAT((table), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: float %f => %p\n", \
|
|
prev_table, (double) value, (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_STRING(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_STRING((table0), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: string `%s' => %p\n", \
|
|
(table), (char *) (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_STRING(table, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_STRING((table), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: string `%s' => %p\n", \
|
|
prev_table, (char *) (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_TYPEINFO(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_TYPEINFO((table0), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: typeinfo %p => %p\n", \
|
|
(table), (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_TYPEINFO(table, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_TYPEINFO((table), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: typeinfo %p => %p\n", \
|
|
prev_table, (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_TYPECLASSINFO(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_TYPECLASSINFO((table0), (value));\
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: typeclassinfo %p => %p\n", \
|
|
(table), (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_TYPECLASSINFO(table, value) \
|
|
do { \
|
|
MR_TrieNode prev_table = (table); \
|
|
(table) = MR_RAW_TABLE_TYPECLASSINFO((table), (value)); \
|
|
if (MR_tabledebug) { \
|
|
printf("TABLE %p: typeclassinfo %p => %p\n", \
|
|
prev_table, (value), (table)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#else /* not MR_TABLE_DEBUG */
|
|
|
|
#define MR_DEBUG_NEW_TABLE_ANY(table, table0, type_info, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_ANY((table0), (type_info), (value));\
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_ANY(table, type_info, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_ANY((table), (type_info), (value));\
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_ANY_FAST_LOOSE(table, table0, type_info, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_ANY_FAST_LOOSE((table0), (type_info), \
|
|
(value)); \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_ANY_FAST_LOOSE(table, type_info, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_ANY_FAST_LOOSE((table), (type_info), \
|
|
(value)); \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_TAG(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_TAG((table0), (value)); \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_TAG(table, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_TAG((table), (value)); \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_ENUM(table, table0, count, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_ENUM((table0), (count), (value));\
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_ENUM(table, count, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_ENUM((table), (count), (value)); \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_START_INT(table, table0, start, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_START_INT((table0), (start), (value));\
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_START_INT(table, start, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_START_INT((table), (start), (value));\
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_WORD(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_WORD((table0), (value)); \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_WORD(table, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_WORD((table), (value));\
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_INT(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_INT((table0), (value)); \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_INT(table, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_INT((table), (value)); \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_CHAR(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_CHAR((table0), (value)); \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_CHAR(table, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_CHAR((table), (value)); \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_FLOAT(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_FLOAT((table0), (value)); \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_FLOAT(table, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_FLOAT((table), (value)); \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_STRING(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_STRING((table0), (value)); \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_STRING(table, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_STRING((table), (value)); \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_TYPEINFO(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_TYPEINFO((table0), (value)); \
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_TYPEINFO(table, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_TYPEINFO((table), (value)); \
|
|
} while (0)
|
|
|
|
#define MR_DEBUG_NEW_TABLE_TYPECLASSINFO(table, table0, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_TYPECLASSINFO((table0), (value));\
|
|
} while (0)
|
|
#define MR_DEBUG_TABLE_TYPECLASSINFO(table, value) \
|
|
do { \
|
|
(table) = MR_RAW_TABLE_TYPECLASSINFO((table), (value)); \
|
|
} while (0)
|
|
|
|
#endif /* MR_TABLE_DEBUG */
|
|
|
|
/***********************************************************************/
|
|
|
|
#ifdef MR_TABLE_DEBUG
|
|
|
|
#define MR_TABLE_CREATE_ANSWER_BLOCK(table, num_slots) \
|
|
do { \
|
|
(table)->MR_answerblock = MR_TABLE_NEW_ARRAY(MR_Word, \
|
|
(num_slots)); \
|
|
if (MR_tabledebug) \
|
|
printf("allocated answer block %p -> %p, %d words\n",\
|
|
(table), (table)->MR_answerblock, \
|
|
(int) (num_slots)); \
|
|
} while(0)
|
|
|
|
#define MR_TABLE_CREATE_NODE_ANSWER_BLOCK(block_ptr, num_slots) \
|
|
do { \
|
|
*block_ptr = MR_TABLE_NEW_ARRAY(MR_Word, (num_slots)); \
|
|
if (MR_tabledebug) \
|
|
printf("allocated node block %p -> %p, %d words\n",\
|
|
block_ptr, *block_ptr, \
|
|
(int) (num_slots)); \
|
|
} while(0)
|
|
|
|
#define MR_TABLE_GET_ANSWER(ab, offset) \
|
|
(( MR_tabledebug ? \
|
|
printf("using answer block: %p, slot %d\n", \
|
|
(ab), (int) (offset)) \
|
|
: \
|
|
(void) 0 /* do nothing */ \
|
|
), \
|
|
(ab)[(offset)])
|
|
|
|
#define MR_TABLE_SAVE_ANSWER(ab, offset, value, type_info) \
|
|
do { \
|
|
if (MR_tabledebug) \
|
|
printf("saving to answer block: %p, " \
|
|
"slot %d = %lx\n", \
|
|
(ab), (int) (offset), (long) (value)); \
|
|
(ab)[offset] = MR_make_permanent((value), \
|
|
(MR_TypeInfo) (type_info)); \
|
|
} while(0)
|
|
|
|
#else
|
|
|
|
#define MR_TABLE_CREATE_ANSWER_BLOCK(table, num_slots) \
|
|
do { \
|
|
(table)->MR_answerblock = MR_TABLE_NEW_ARRAY(MR_Word, \
|
|
(num_slots)); \
|
|
} while(0)
|
|
|
|
#define MR_TABLE_CREATE_NODE_ANSWER_BLOCK(block_ptr, num_slots) \
|
|
do { \
|
|
*block_ptr = MR_TABLE_NEW_ARRAY(MR_Word, (num_slots)); \
|
|
} while(0)
|
|
|
|
#define MR_TABLE_GET_ANSWER(ab, offset) \
|
|
(ab)[(offset)]
|
|
|
|
#define MR_TABLE_SAVE_ANSWER(ab, offset, value, type_info) \
|
|
do { \
|
|
(ab)[offset] = MR_make_permanent((value), \
|
|
(MR_TypeInfo) (type_info)); \
|
|
} while(0)
|
|
|
|
#endif
|