summaryrefslogtreecommitdiff
path: root/coregrind/.svn/text-base/m_sparsewa.c.svn-base
diff options
context:
space:
mode:
Diffstat (limited to 'coregrind/.svn/text-base/m_sparsewa.c.svn-base')
-rw-r--r--coregrind/.svn/text-base/m_sparsewa.c.svn-base478
1 files changed, 478 insertions, 0 deletions
diff --git a/coregrind/.svn/text-base/m_sparsewa.c.svn-base b/coregrind/.svn/text-base/m_sparsewa.c.svn-base
new file mode 100644
index 0000000..e8f4965
--- /dev/null
+++ b/coregrind/.svn/text-base/m_sparsewa.c.svn-base
@@ -0,0 +1,478 @@
+
+/*--------------------------------------------------------------------*/
+/*--- An sparse array (of words) implementation. ---*/
+/*--- m_sparsewa.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2008-2009 OpenWorks Ltd
+ info@open-works.co.uk
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_sparsewa.h" /* self */
+
+/////////////////////////////////////////////////////////
+// //
+// SparseWA: Implementation //
+// //
+/////////////////////////////////////////////////////////
+
+//////// SWA data structures
+
+// (UInt) `echo "Level Zero Byte Map" | md5sum`
+#define Level0_MAGIC 0x458ec222
+
+// (UInt) `echo "Level N Byte Map" | md5sum`
+#define LevelN_MAGIC 0x0a280a1a
+
+/* It's important that the .magic field appears at offset zero in both
+ structs, so that we can reliably distinguish between them. */
+
+typedef
+ struct {
+ UWord magic;
+ UWord words[256];
+ Int nInUse;
+ UChar inUse[256/8];
+ }
+ Level0;
+
+typedef
+ struct {
+ UWord magic;
+ void* child[256]; /* either LevelN* or Level0* */
+ Int nInUse;
+ Int level; /* 3 .. 1 on 32-bit, 7 .. 1 on 64-bit */
+ }
+ LevelN;
+
+typedef
+ struct {
+ UWord partial_key;
+ Int curr_ix;
+ void* curr_nd; /* LevelN* or Level0* */
+ Int resume_point; /* 1, 2 or 3 */
+ }
+ SWAStackElem;
+
+struct _SparseWA {
+ void* (*alloc_nofail)(HChar*,SizeT);
+ HChar* cc;
+ void (*dealloc)(void*);
+ LevelN* root;
+ SWAStackElem iterStack[8];
+ Int isUsed;
+};
+
+//////// SWA helper functions (bitarray)
+
+static inline UWord swa_bitarray_read ( UChar* arr, UWord ix ) {
+ UWord bix = ix >> 3;
+ UWord off = ix & 7;
+ return (arr[bix] >> off) & 1;
+}
+
+static inline UWord swa_bitarray_read_then_set ( UChar* arr, UWord ix ) {
+ UWord bix = ix >> 3;
+ UWord off = ix & 7;
+ UChar old = arr[bix];
+ UChar nyu = old | (1 << off);
+ arr[bix] = nyu;
+ return (old >> off) & 1;
+}
+
+static inline UWord swa_bitarray_read_then_clear ( UChar* arr, UWord ix ) {
+ UWord bix = ix >> 3;
+ UWord off = ix & 7;
+ UChar old = arr[bix];
+ UChar nyu = old & ~(1 << off);
+ arr[bix] = nyu;
+ return (old >> off) & 1;
+}
+
+//////// SWA helper functions (iteration)
+
+static void swa_PUSH ( SparseWA* swa, UWord partial_key, Int curr_ix,
+ void* curr_nd, Int resume_point )
+{
+ Int sp = swa->isUsed;
+ const Int _3_or_7 = sizeof(void*) - 1;
+ // if (0) VG_(printf)("PUSH, old sp = %d\n", sp);
+ vg_assert(sp >= 0 && sp <= _3_or_7);
+ swa->iterStack[sp].partial_key = partial_key;
+ swa->iterStack[sp].curr_ix = curr_ix;
+ swa->iterStack[sp].curr_nd = curr_nd;
+ swa->iterStack[sp].resume_point = resume_point;
+ swa->isUsed = sp+1;
+}
+
+static void swa_POP ( SparseWA* swa,
+ UWord* partial_key, Int* curr_ix,
+ void** curr_nd, Int* resume_point )
+{
+ Int sp = swa->isUsed - 1;
+ const Int _3_or_7 = sizeof(void*) - 1;
+ // if (0) VG_(printf)("POP, old sp = %d\n", sp+1);
+ vg_assert(sp >= 0 && sp <= _3_or_7);
+ *partial_key = swa->iterStack[sp].partial_key;
+ *curr_ix = swa->iterStack[sp].curr_ix;
+ *curr_nd = swa->iterStack[sp].curr_nd;
+ *resume_point = swa->iterStack[sp].resume_point;
+ swa->isUsed = sp;
+}
+
+//////// SWA helper functions (allocation)
+
+static LevelN* swa_new_LevelN ( SparseWA* swa, Int level )
+{
+ LevelN* levelN = swa->alloc_nofail( swa->cc, sizeof(LevelN) );
+ VG_(memset)(levelN, 0, sizeof(*levelN));
+ levelN->magic = LevelN_MAGIC;
+ levelN->level = level;
+ return levelN;
+}
+
+static Level0* swa_new_Level0 ( SparseWA* swa )
+{
+ Level0* level0 = swa->alloc_nofail( swa->cc, sizeof(Level0) );
+ VG_(memset)(level0, 0, sizeof(*level0));
+ level0->magic = Level0_MAGIC;
+ return level0;
+}
+
+
+//////// SWA public interface
+
+void VG_(initIterSWA) ( SparseWA* swa )
+{
+ swa->isUsed = 0;
+ if (swa->root) swa_PUSH(swa, 0, 0, swa->root, 1/*start_new_node*/);
+}
+
+
+Bool VG_(nextIterSWA)( SparseWA* swa,
+ /*OUT*/UWord* keyP, /*OUT*/UWord* valP )
+{
+ UWord p_key;
+ Int curr_ix;
+ void* curr_nd;
+ Int resume_point;
+
+ /* dispatch whatever's on top of the stack; what that actually
+ means is to return to some previously-saved context. */
+ dispatch:
+
+ if (swa->isUsed == 0)
+ return False;
+
+ swa_POP(swa, &p_key, &curr_ix, &curr_nd, &resume_point);
+ switch (resume_point) {
+ case 1: goto start_new_node;
+ case 2: goto resume_leaf_node;
+ case 3: goto resume_nonleaf_node;
+ default: vg_assert(0);
+ }
+
+ start_new_node:
+ if (*(UWord*)curr_nd == Level0_MAGIC) {
+ /* curr_nd is a leaf node */
+ Level0* level0 = (Level0*)curr_nd;
+ for (curr_ix = 0; curr_ix < 256; curr_ix++) {
+ if (swa_bitarray_read(level0->inUse, curr_ix) == 1) {
+ swa_PUSH(swa, p_key, curr_ix, curr_nd, 2/*resume_leaf_node*/);
+ *keyP = (p_key << 8) + (UWord)curr_ix;
+ *valP = level0->words[curr_ix];
+ return True;
+ resume_leaf_node:
+ level0 = (Level0*)curr_nd;
+ }
+ }
+ } else {
+ /* curr_nd is a non-leaf node */
+ LevelN* levelN;
+ vg_assert(*(UWord*)curr_nd == LevelN_MAGIC);
+ levelN = (LevelN*)curr_nd;
+ for (curr_ix = 0; curr_ix < 256; curr_ix++) {
+ if (levelN->child[curr_ix]) {
+ swa_PUSH(swa, p_key, curr_ix, curr_nd, 3/*resume_nonleaf_node*/);
+ p_key = (p_key << 8) + (UWord)curr_ix;
+ curr_nd = levelN->child[curr_ix];
+ goto start_new_node;
+ resume_nonleaf_node:
+ levelN = (LevelN*)curr_nd;
+ }
+ }
+ }
+
+ goto dispatch;
+}
+
+
+SparseWA* VG_(newSWA) ( void*(*alloc_nofail)(HChar* cc, SizeT),
+ HChar* cc,
+ void(*dealloc)(void*) )
+{
+ SparseWA* swa;
+ vg_assert(alloc_nofail);
+ vg_assert(cc);
+ vg_assert(dealloc);
+ swa = alloc_nofail( cc, sizeof(SparseWA) );
+ VG_(memset)(swa, 0, sizeof(*swa));
+ swa->alloc_nofail = alloc_nofail;
+ swa->cc = cc;
+ swa->dealloc = dealloc;
+ swa->root = NULL;
+ return swa;
+}
+
+
+static void swa_deleteSWA_wrk ( void(*dealloc)(void*), void* nd )
+{
+ Int i;
+ vg_assert(nd);
+ if (*(UWord*)nd == LevelN_MAGIC) {
+ LevelN* levelN = (LevelN*)nd;
+ for (i = 0; i < 256; i++) {
+ if (levelN->child[i]) {
+ swa_deleteSWA_wrk( dealloc, levelN->child[i] );
+ }
+ }
+ } else {
+ vg_assert(*(UWord*)nd == Level0_MAGIC);
+ }
+ dealloc(nd);
+}
+void VG_(deleteSWA) ( SparseWA* swa )
+{
+ if (swa->root)
+ swa_deleteSWA_wrk( swa->dealloc, swa->root );
+ swa->dealloc(swa);
+}
+
+
+Bool VG_(lookupSWA) ( SparseWA* swa,
+ /*OUT*/UWord* keyP, /*OUT*/UWord* valP,
+ UWord key )
+{
+ Int i;
+ UWord ix;
+ Level0* level0;
+ LevelN* levelN;
+ const Int _3_or_7 = sizeof(void*) - 1;
+
+ vg_assert(swa);
+ levelN = swa->root;
+
+ /* levels 3/7 .. 1 */
+ for (i = _3_or_7; i >= 1; i--) {
+ if (!levelN) return False;
+ vg_assert(levelN->level == i);
+ vg_assert(levelN->nInUse > 0);
+ ix = (key >> (i*8)) & 0xFF;
+ levelN = levelN->child[ix];
+ }
+
+ /* level0 */
+ level0 = (Level0*)levelN;
+ if (!level0) return False;
+ vg_assert(level0->magic == Level0_MAGIC);
+ vg_assert(level0->nInUse > 0);
+ ix = key & 0xFF;
+ if (swa_bitarray_read(level0->inUse, ix) == 0) return False;
+ *keyP = key; /* this is stupid. only here to make it look like WordFM */
+ *valP = level0->words[ix];
+ return True;
+}
+
+
+Bool VG_(addToSWA) ( SparseWA* swa, UWord key, UWord val )
+{
+ Int i;
+ UWord ix;
+ Level0* level0;
+ LevelN* levelN;
+ Bool already_present;
+ const Int _3_or_7 = sizeof(void*) - 1;
+
+ vg_assert(swa);
+
+ if (!swa->root)
+ swa->root = swa_new_LevelN(swa, _3_or_7);
+ levelN = swa->root;
+
+ /* levels 3/7 .. 2 */
+ for (i = _3_or_7; i >= 2; i--) {
+ /* levelN is the level-i map */
+ vg_assert(levelN);
+ vg_assert(levelN->level == i);
+ ix = (key >> (i*8)) & 0xFF;
+ if (levelN->child[ix] == NULL) {
+ levelN->child[ix] = swa_new_LevelN(swa, i-1);
+ levelN->nInUse++;
+ }
+ vg_assert(levelN->nInUse >= 1 && levelN->nInUse <= 256);
+ levelN = levelN->child[ix];
+ }
+
+ /* levelN is the level-1 map */
+ vg_assert(levelN);
+ vg_assert(levelN->level == 1);
+ ix = (key >> (1*8)) & 0xFF;
+ if (levelN->child[ix] == NULL) {
+ levelN->child[ix] = swa_new_Level0(swa);
+ levelN->nInUse++;
+ }
+ vg_assert(levelN->nInUse >= 1 && levelN->nInUse <= 256);
+ level0 = levelN->child[ix];
+
+ /* level0 is the level-0 map */
+ vg_assert(level0);
+ vg_assert(level0->magic == Level0_MAGIC);
+ ix = key & 0xFF;
+ if (swa_bitarray_read_then_set(level0->inUse, ix) == 0) {
+ level0->nInUse++;
+ already_present = False;
+ } else {
+ already_present = True;
+ }
+ vg_assert(level0->nInUse >= 1 && level0->nInUse <= 256);
+ level0->words[ix] = val;
+
+ return already_present;
+}
+
+
+Bool VG_(delFromSWA) ( SparseWA* swa,
+ /*OUT*/UWord* oldK, /*OUT*/UWord* oldV, UWord key )
+{
+ Int i;
+ UWord ix;
+ Level0* level0;
+ LevelN* levelN;
+ const Int _3_or_7 = sizeof(void*) - 1;
+
+ LevelN* visited[_3_or_7];
+ UWord visitedIx[_3_or_7];
+ Int nVisited = 0;
+
+ vg_assert(swa);
+ levelN = swa->root;
+
+ /* levels 3/7 .. 1 */
+ for (i = _3_or_7; i >= 1; i--) {
+ /* level i */
+ if (!levelN) return False;
+ vg_assert(levelN->level == i);
+ vg_assert(levelN->nInUse > 0);
+ ix = (key >> (i*8)) & 0xFF;
+ visited[nVisited] = levelN;
+ visitedIx[nVisited++] = ix;
+ levelN = levelN->child[ix];
+ }
+
+ /* level 0 */
+ level0 = (Level0*)levelN;
+ if (!level0) return False;
+ vg_assert(level0->magic == Level0_MAGIC);
+ vg_assert(level0->nInUse > 0);
+ ix = key & 0xFF;
+
+ if (swa_bitarray_read_then_clear(level0->inUse, ix) == 0)
+ return False;
+
+ *oldK = key; /* this is silly */
+ *oldV = level0->words[ix];
+
+ level0->nInUse--;
+ if (level0->nInUse > 0)
+ return True;
+
+ vg_assert(nVisited == _3_or_7);
+ swa->dealloc( level0 );
+
+ /* levels 1 .. 3/7 */
+ for (i = 1; i <= _3_or_7; i++) {
+ /* level i */
+ nVisited--;
+ vg_assert(visited[nVisited]->child[ visitedIx[nVisited] ]);
+ visited[nVisited]->child[ visitedIx[nVisited] ] = NULL;
+ visited[nVisited]->nInUse--;
+ vg_assert(visited[nVisited]->nInUse >= 0);
+ if (visited[nVisited]->nInUse > 0)
+ return True;
+ swa->dealloc(visited[nVisited]);
+ }
+
+ vg_assert(nVisited == 0);
+ swa->root = NULL;
+ return True;
+}
+
+
+static UWord swa_sizeSWA_wrk ( void* nd )
+{
+ Int i;
+ UWord sum = 0;
+ if (*(UWord*)nd == LevelN_MAGIC) {
+ LevelN* levelN = (LevelN*)nd;
+ for (i = 0; i < 256; i++) {
+ if (levelN->child[i]) {
+ sum += swa_sizeSWA_wrk( levelN->child[i] );
+ }
+ }
+ } else {
+ Level0* level0;
+ vg_assert(*(UWord*)nd == Level0_MAGIC);
+ level0 = (Level0*)nd;
+ for (i = 0; i < 256/8; i += 2) {
+ UWord x = level0->inUse[i+0]; /* assume zero-extend */
+ UWord y = level0->inUse[i+1]; /* assume zero-extend */
+ /* do 'sum += popcount(x) + popcount(y)' for byte-sized x, y */
+ /* unroll the loop twice so as to expose more ILP */
+ x = (x & 0x55) + ((x >> 1) & 0x55);
+ y = (y & 0x55) + ((y >> 1) & 0x55);
+ x = (x & 0x33) + ((x >> 2) & 0x33);
+ y = (y & 0x33) + ((y >> 2) & 0x33);
+ x = (x & 0x0F) + ((x >> 4) & 0x0F);
+ y = (y & 0x0F) + ((y >> 4) & 0x0F);
+ sum += x + y;
+ }
+ }
+ return sum;
+}
+UWord VG_(sizeSWA) ( SparseWA* swa )
+{
+ if (swa->root)
+ return swa_sizeSWA_wrk ( swa->root );
+ else
+ return 0;
+}
+
+
+
+/*--------------------------------------------------------------------*/
+/*--- end m_sparsewa.c ---*/
+/*--------------------------------------------------------------------*/