#ifndef STORAGE_H
#define STORAGE_H

#include "allocate.h"
#include "lib.h"

/*
 * The "storage" that underlies an incoming/outgoing pseudo. It's
 * basically the backing store for a pseudo, and may be a real hardware
 * register, a stack slot or a static symbol. Or nothing at all,
 * since some pseudos can just be recalculated on the fly.
 */
enum storage_type {
	REG_UDEF,
	REG_REG,
	REG_STACK,
	REG_FRAME,
	REG_SYM,
	REG_ARG,
	REG_BAD,
};

enum inout_enum {
	STOR_IN,
	STOR_OUT
};

struct storage;
DECLARE_PTR_LIST(storage_ptr_list, struct storage *);

struct storage {
	enum storage_type type;
	int name;
	struct storage_ptr_list *users;
	union {
		int regno;
		int offset;
		struct symbol *sym;
	};
};

DECLARE_PTR_LIST(storage_list, struct storage);

struct storage_hash {
	struct basic_block *bb;
	pseudo_t pseudo;
	enum inout_enum inout;
	struct storage *storage;
	unsigned long flags;
};

DECLARE_PTR_LIST(storage_hash_list, struct storage_hash);

extern struct storage_hash_list *gather_storage(SCTX_ struct basic_block *, enum inout_enum);
extern void free_storage(SCTX);
extern const char *show_storage(SCTX_ struct storage *);
extern void set_up_storage(SCTX_ struct entrypoint *);
struct storage *lookup_storage(SCTX_ struct basic_block *, pseudo_t, enum inout_enum);
void add_storage(SCTX_ struct storage *, struct basic_block *, pseudo_t, enum inout_enum);

DECLARE_ALLOCATOR(storage);
DECLARE_ALLOCATOR(storage_hash);

static inline struct storage *alloc_storage(SCTX)
{
	return __alloc_storage(sctx_ 0);
}

static inline struct storage_hash *alloc_storage_hash(SCTX_ struct storage *s)
{
	struct storage_hash *entry = __alloc_storage_hash(sctx_ 0);
	struct storage **usep = &entry->storage;

	*usep = s;
	add_ptr_list(&s->users, usep);
	return entry;
}

#endif /* STORAGE_H */
