blob: 212ab2f00714aa3f25e1d327cb01bc86dc2d6a52 [file] [log] [blame]
/* Caching values "in" trees
Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GCC.
GCC 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, or (at your option) any later
version.
GCC 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 GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
//===----------------------------------------------------------------------===//
// This code lets you to associate a void* with a tree, as if it were cached
// inside the tree: if the tree is garbage collected and reallocated, then the
// cached value will have been cleared.
//===----------------------------------------------------------------------===//
// Plugin headers
#include "llvm-cache.h"
// GCC headers
#include "ggc.h"
struct GTY(()) tree_llvm_map {
struct tree_map_base base;
const void * GTY((skip)) val;
};
#define tree_llvm_map_eq tree_map_base_eq
#define tree_llvm_map_hash tree_map_base_hash
#define tree_llvm_map_marked_p tree_map_base_marked_p
static GTY ((if_marked ("tree_llvm_map_marked_p"),
param_is(struct tree_llvm_map)))
htab_t llvm_cache;
/// llvm_has_cached - Returns whether a value has been associated with the tree.
bool llvm_has_cached(union tree_node *tree) {
struct tree_map_base in;
if (!llvm_cache)
return false;
in.from = tree;
return htab_find(llvm_cache, &in) != NULL;
}
/// llvm_get_cached - Returns the value associated with the tree, or NULL.
const void *llvm_get_cached(union tree_node *tree) {
struct tree_llvm_map *h;
struct tree_map_base in;
if (!llvm_cache)
return NULL;
in.from = tree;
h = (struct tree_llvm_map *) htab_find(llvm_cache, &in);
return h ? h->val : NULL;
}
/// llvm_set_cached - Associates the given value with the tree (and returns it).
/// To delete an association, pass a NULL value here.
const void *llvm_set_cached(union tree_node *tree, const void *val) {
struct tree_llvm_map **slot;
struct tree_map_base in;
in.from = tree;
// If deleting, remove the slot.
if (val == NULL) {
if (llvm_cache)
htab_remove_elt(llvm_cache, &in);
return NULL;
}
if (!llvm_cache)
llvm_cache = htab_create_ggc(1024, tree_llvm_map_hash, tree_llvm_map_eq, NULL);
slot = (struct tree_llvm_map **) htab_find_slot(llvm_cache, &in, INSERT);
gcc_assert(slot);
if (!*slot) {
*slot = GGC_NEW(struct tree_llvm_map);
(*slot)->base.from = tree;
}
(*slot)->val = val;
return val;
}
struct update {
const void *old_val;
const void *new_val;
};
/// replace - If the current value for the slot matches old_val, then replace
/// it with new_val, or delete it if new_val is NULL.
static int replace(void **slot, void *data) {
struct tree_llvm_map *entry = *(struct tree_llvm_map **)slot;
struct update *u = (struct update *)data;
if (entry->val != u->old_val)
return 1;
if (u->new_val != NULL)
entry->val = u->new_val;
else
htab_clear_slot(llvm_cache, slot);
return 1;
}
/// llvm_replace_cached - Replaces all occurrences of old_val with new_val.
void llvm_replace_cached(const void *old_val, const void *new_val) {
struct update u = { old_val, new_val };
if (!llvm_cache || old_val == NULL)
return;
htab_traverse(llvm_cache, replace, &u);
}
#include "gt-llvm-cache.h"