blob: 5fd3f1cfcf2d9862caa99b140572a9a77e55313a [file] [log] [blame]
//==----------- Cache.h - Caching values "in" GCC trees ----------*- C++ -*-==//
//
// Copyright (C) 2009 to 2013 Duncan Sands.
//
// This file is part of DragonEgg.
//
// DragonEgg 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.
//
// DragonEgg 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 DragonEgg; see the file COPYING. If not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
//
//===----------------------------------------------------------------------===//
// This code lets you associate values 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 "dragonegg/Cache.h"
// LLVM headers
#include "llvm/IR/ValueHandle.h"
// System headers
#include <cassert>
#include <gmp.h>
// GCC headers
#include "auto-host.h"
#ifndef ENABLE_BUILD_WITH_CXX
#include <cstring> // Otherwise included by system.h with C linkage.
extern "C" {
#endif
#include "config.h"
// Stop GCC declaring 'getopt' as it can clash with the system's declaration.
#undef HAVE_DECL_GETOPT
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "ggc.h"
#ifndef ENABLE_BUILD_WITH_CXX
} // extern "C"
#endif
using namespace llvm;
// Hash table mapping trees to integers.
struct GTY(()) tree2int {
struct tree_map_base base;
int GTY((skip)) val;
};
#define tree2int_eq tree_map_base_eq
#define tree2int_hash tree_map_base_hash
#define tree2int_marked_p tree_map_base_marked_p
static GTY((if_marked("tree2int_marked_p"), param_is(struct tree2int)))
htab_t intCache;
// Hash table mapping trees to Type*.
// Forward declare Type for the benefit of gengtype.
#ifndef IN_GCC
struct Type;
#endif
struct GTY(()) tree2Type {
struct tree_map_base base;
#ifndef IN_GCC
struct
#endif
Type *
GTY((skip)) Ty;
};
#define tree2Type_eq tree_map_base_eq
#define tree2Type_hash tree_map_base_hash
#define tree2Type_marked_p tree_map_base_marked_p
static GTY((if_marked("tree2Type_marked_p"), param_is(struct tree2Type)))
htab_t TypeCache;
// Hash table mapping trees to WeakVH.
// Forward declare WeakVH for the benefit of gengtype.
#ifndef IN_GCC
struct WeakVH;
#endif
struct GTY(()) tree2WeakVH {
struct tree_map_base base;
#ifndef IN_GCC
struct
#endif
WeakVH
GTY((skip)) V;
};
#define tree2WeakVH_eq tree_map_base_eq
#define tree2WeakVH_hash tree_map_base_hash
#define tree2WeakVH_marked_p tree_map_base_marked_p
static GTY((if_marked("tree2WeakVH_marked_p"), param_is(struct tree2WeakVH)))
htab_t WeakVHCache;
// Include the garbage collector header.
#ifndef ENABLE_BUILD_WITH_CXX
extern "C" {
#endif
#if (GCC_MINOR > 5)
#include "dragonegg/gt-cache-4.6.inc"
#else
#include "dragonegg/gt-cache-4.5.inc"
#endif
#ifndef ENABLE_BUILD_WITH_CXX
} // extern "C"
#endif
bool getCachedInteger(tree t, int &Val) {
if (!intCache)
return false;
tree_map_base in = { t };
tree2int *h = (tree2int *)htab_find(intCache, &in);
if (!h)
return false;
Val = h->val;
return true;
}
void setCachedInteger(tree t, int Val) {
if (!intCache)
intCache = htab_create_ggc(1024, tree2int_hash, tree2int_eq, 0);
tree_map_base in = { t };
tree2int **slot = (tree2int **)htab_find_slot(intCache, &in, INSERT);
assert(slot && "Failed to create hash table slot!");
if (!*slot) {
*slot =
#if (GCC_MINOR > 5)
ggc_alloc_tree2int();
#else
GGC_NEW(struct tree2int);
#endif
(*slot)->base.from = t;
}
(*slot)->val = Val;
}
Type *getCachedType(tree t) {
if (!TypeCache)
return 0;
tree_map_base in = { t };
tree2Type *h = (tree2Type *)htab_find(TypeCache, &in);
return h ? h->Ty : 0;
}
void setCachedType(tree t, Type *Ty) {
tree_map_base in = { t };
/* If deleting, remove the slot. */
if (!Ty) {
if (TypeCache)
htab_remove_elt(TypeCache, &in);
return;
}
if (!TypeCache)
TypeCache = htab_create_ggc(1024, tree2Type_hash, tree2Type_eq, 0);
tree2Type **slot = (tree2Type **)htab_find_slot(TypeCache, &in, INSERT);
assert(slot && "Failed to create hash table slot!");
if (!*slot) {
*slot =
#if (GCC_MINOR > 5)
ggc_alloc_tree2Type();
#else
GGC_NEW(struct tree2Type);
#endif
(*slot)->base.from = t;
}
(*slot)->Ty = Ty;
}
/// getCachedValue - Returns the value associated with the given GCC tree, or
/// null if none.
Value *getCachedValue(tree t) {
if (!WeakVHCache)
return 0;
tree_map_base in = { t };
tree2WeakVH *h = (tree2WeakVH *)htab_find(WeakVHCache, &in);
return h ? h->V : 0;
}
static void DestructWeakVH(void *p) {
((WeakVH *)&((tree2WeakVH *)p)->V)->~WeakVH();
}
/// setCachedValue - Associates the given value (which may be null) with the
/// given GCC tree. The association is removed if tree is garbage collected
/// or the value deleted.
void setCachedValue(tree t, Value *V) {
tree_map_base in = { t };
// If deleting, remove the slot.
if (!V) {
if (WeakVHCache)
htab_remove_elt(WeakVHCache, &in);
return;
}
if (!WeakVHCache)
WeakVHCache =
htab_create_ggc(1024, tree2WeakVH_hash, tree2WeakVH_eq, DestructWeakVH);
tree2WeakVH **slot = (tree2WeakVH **)htab_find_slot(WeakVHCache, &in, INSERT);
assert(slot && "Failed to create hash table slot!");
if (*slot) {
(*slot)->V = V;
return;
}
*slot =
#if (GCC_MINOR > 5)
ggc_alloc_tree2WeakVH();
#else
GGC_NEW(struct tree2WeakVH);
#endif
(*slot)->base.from = t;
WeakVH *W = new (&(*slot)->V) WeakVH(V);
assert(W == &(*slot)->V && "Pointer was displaced!");
(void)W;
}