Commit 8e0086df authored by Sebastian Hack's avatar Sebastian Hack
Browse files

Added be arch reflection/backend support infrastructure.

parent 1a417753
......@@ -23,7 +23,7 @@ SOURCES += Makefile.in besched.h belistsched.h belistsched.c \
beutil.h bemain.c besched.c bemain.c belive.c belive.h benumb.h \
benumb_t.h benumb.c bechordal.c bera.c beutil.c phistat.c \
bephiopt.c bephicoal.c bera.h bechordalspill.c \
beasm_dump_globals.c beasm_asm_gnu.c
beasm_dump_globals.c beasm_asm_gnu.c bearch.h bearch.c
include $(topdir)/MakeRules
......
/**
* Processor architecture specification.
* @author Sebastian Hack
* @date 11.2.2005
*
* $Id$
*/
#include "bearch_t.h"
#include "firm_config.h"
#include "set.h"
#include "entity.h"
#include "ircons_t.h"
#if 1 /* HAVE_ALLOCA_H */
#include <alloca.h>
#endif /* HAVE_ALLOCA_H */
#define INIT_HEADER(tgt, kind_suffix, a_isa, str) \
do { \
arch_header_t *h = (arch_header_t *) (tgt); \
memset(tgt, 0, sizeof(*(tgt))); \
h->kind = arch_kind_ ## kind_suffix; \
h->name = new_id_from_str(str); \
h->isa = a_isa; \
} while(0)
static INLINE int hash_header(const arch_header_t *header)
{
int res = HASH_PTR(header->isa);
res = 37 * res + HASH_STR(header->name, strlen(header->name));
res = 37 * res + header->kind;
return res;
}
static int cmp_header(const void *a, const void *b, size_t size)
{
const arch_header_t *h1 = a;
const arch_header_t *h2 = b;
return !(h1->kind == h2->kind && strcmp(h1->name, h2->name) == 0);
}
static set *arch_data = NULL;
static set *get_arch_data(void)
{
if(!arch_data)
arch_data = new_set(cmp_header, 256);
return arch_data;
}
typedef struct _obj_info_t {
const char *name;
int listed_in_isa;
size_t size;
} obj_info_t;
static const obj_info_t obj_info[] = {
#define ARCH_OBJ(name,listed_in_isa) { #name, listed_in_isa, sizeof(arch_ ## name ## _t) },
#include "bearch_obj.def"
#undef ARCH_OBJ
{ 0 }
};
/**
* Insert an arch object to the global arch obj storage.
*
* If the object has already been created there, nothing is done and
* the old object is created.
*
* @param kind The kind of the arch object.
* @param isa The isa the object belongs to or NULL if it is the isa
* itself.
* @param name The name of the object.
* @param was_new A pointer to an int where 1/0 is stored if the
* object was created or already present. If NULL, it is simply ignored.
* @return A pointer to the object.
*/
static INLINE void *_arch_data_insert(arch_kind_t kind, arch_isa_t *isa,
const char *name, size_t size, int *was_new)
{
const obj_info_t *info = &obj_info[kind];
arch_header_t *data = alloca(size);
arch_header_t *res = NULL;
memset(data, 0, size);
data->kind = kind;
data->isa = isa;
data->name = get_id_str(new_id_from_str(name));
data->is_new = 1;
res = set_insert(get_arch_data(), data, size, hash_header(data));
/* If the object is newly created and thus not yet present
* in the set, add it to the isa */
if(res->is_new) {
/*
* The inserted object was no isa, list it in the isa if this is
* desired.
*/
if(isa && info->listed_in_isa)
list_add(&res->list, &isa->heads[kind]);
/* The inserted object is an isa, so initialize all its list heads. */
else {
int i;
arch_isa_t *isa = (arch_isa_t *) res;
for(i = 0; i < arch_kind_last; ++i)
INIT_LIST_HEAD(&isa->heads[i]);
}
}
/*
* If the caller wants to know, of the object was newly created,
* give it to him.
*/
if(was_new)
*was_new = res->is_new;
/* Mark the object as NOT new. */
res->is_new = 0;
return res;
}
#define arch_data_insert(type_suffix, isa, name, was_new) \
_arch_data_insert(arch_kind_ ## type_suffix, isa, name, sizeof(arch_ ## type_suffix ## _t), was_new)
static INLINE void *_arch_data_find(arch_kind_t kind, const arch_isa_t *isa, const char *name)
{
arch_header_t header;
memset(&header, 0, sizeof(header));
header.kind = kind;
header.isa = (arch_isa_t *) isa;
header.name = name;
return set_find(get_arch_data(), &header, sizeof(header), hash_header(&header));
}
#define arch_data_find(type_suffix, isa, name) \
_arch_data_find(arch_kind_ ## type_suffix, isa, name)
arch_isa_t *arch_add_isa(const char *name)
{
return arch_data_insert(isa, NULL, name, NULL);
}
arch_register_class_t *arch_add_register_class(arch_isa_t *isa, const char *name, int n_regs)
{
arch_register_class_t *cls =
_arch_data_insert(arch_kind_register_class, isa, name,
sizeof(arch_register_class_t) + n_regs * sizeof(arch_register_t *), NULL);
cls->n_regs = n_regs;
return cls;
}
arch_register_t *arch_add_register(arch_register_class_t *cls, int index, const char *name)
{
arch_register_t *reg = NULL;
assert(index >= 0 && index < cls->n_regs);
reg = _arch_data_insert(arch_kind_register, arch_obj_get_isa(cls), name,
sizeof(arch_register_t), NULL);
cls->regs[index] = reg;
reg->index = index;
reg->reg_class = cls;
reg->flags = arch_register_flag_none;
return reg;
}
arch_immediate_t *arch_add_immediate(arch_isa_t *isa, const char *name, ir_mode *mode)
{
arch_immediate_t *imm = arch_data_insert(immediate, isa, name, NULL);
imm->mode = mode;
return imm;
}
static const size_t operand_sizes[] = {
0,
0,
sizeof(entity *),
sizeof(arch_register_t *),
sizeof(tarval *)
};
arch_insn_format_t *arch_add_insn_format(arch_isa_t *isa, const char *name, int n_in, int n_out)
{
int i;
arch_insn_format_t *fmt =
_arch_data_insert(arch_kind_insn_format, isa, name,
sizeof(arch_insn_format_t) + (n_in + n_out) * sizeof(arch_operand_type_t), NULL);
fmt->n_in = n_in;
fmt->n_out = n_out;
fmt->irn_data_size = 0;
/*
* Compute the number of bytes which must be extra allocated if this
* opcode is instantiated.
*/
for(i = 0; i < fmt->n_in; ++i) {
arch_operand_t *op = arch_get_in_operand(fmt, i);
op->offset_in_irn_data = fmt->irn_data_size;
fmt->irn_data_size += operand_sizes[op->type];
}
if(fmt->n_out == 1) {
arch_operand_t *op = arch_get_in_operand(fmt, i);
op->offset_in_irn_data = fmt->irn_data_size;
fmt->irn_data_size += operand_sizes[op->type];
}
return fmt;
}
arch_insn_t *arch_add_insn(arch_insn_format_t *fmt, const char *name)
{
/* Insert the insn into the isa. */
arch_insn_t *insn = arch_data_insert(insn, arch_obj_get_isa(fmt), name, NULL);
insn->format = fmt;
insn->op = new_ir_op(get_next_ir_opcode(), name, op_pin_state_pinned, 0,
oparity_dynamic, 0, sizeof(arch_irn_data_t) + fmt->irn_data_size);
return insn;
}
arch_insn_format_t *arch_find_insn_format(arch_isa_t *isa, const char *name)
{
return arch_data_find(insn_format, isa, name);
}
arch_isa_t *arch_find_isa(const char *name)
{
return arch_data_find(isa, NULL, name);
}
arch_register_class_t *arch_find_register_class_t(arch_isa_t *isa, const char *name)
{
return arch_data_find(register_class, isa, name);
}
arch_register_set_t *arch_get_register_set_for_class(arch_register_class_t *cls)
{
return _arch_get_register_set_for_class(cls);
}
ir_node *arch_new_node(const arch_insn_t *insn, ir_graph *irg, ir_node *block,
ir_mode *mode, int arity, ir_node **in)
{
ir_node *irn = new_ir_node(NULL, irg, block, insn->op, mode, arity, in);
arch_irn_data_t *data = (void *) &irn->attr;
data->magic = ARCH_IRN_FOURCC;
data->insn = insn;
return irn;
}
ir_node *arch_new_node_bare(const arch_insn_t *insn, ir_graph *irg, int arity)
{
int i;
ir_node **in = alloca(sizeof(in[0]) * arity);
for(i = 0; i < arity; ++i)
in[i] = new_Unknown(mode_Is);
return arch_new_node(insn, irg, new_Unknown(mode_BB), mode_Is, arity, in);
}
#ifndef _FIRM_BEARCH_H
#define _FIRM_BEARCH_H
#include "bitset.h"
/*
* Define the types of the arch facility.
* All arch object names are stored in bearch_obj.def
*/
#define ARCH_OBJ(x,list) typedef struct _arch_ ## x ## _t arch_ ## x ## _t;
#include "bearch_obj.def"
#undef ARCH_OBJ
/**
* A callback to determine the set of valid registers.
*
* @param irn The node which represents an instance of the instruction.
* @param pos The number of the insn's operand to consider.
* @param valid_regs A bitset where all valid registers are put.
*/
typedef void (arch_register_callback_t)(ir_node *irn, int pos, bitset_t *valid_regs);
/**
* Add a new instruction set architecture.
* @param name The name of the isa.
* @return The isa object.
*/
arch_isa_t *arch_add_isa(const char *name);
/**
* Add a register class to the isa.
* @param isa The isa to add the reg class to.
* @param name The name of the register class.
* @param n_regs The number of registers in that class.
* @param mode The mode of the registers in that class.
*/
arch_register_class_t *arch_add_register_class(arch_isa_t *isa, const char *name, int n_regs);
/**
* Add a register to a register class.
* @param cls The register class.
* @param index The index of the register (its number within the
* class).
* @param name The name of the register.
* @return The register.
*/
arch_register_t *arch_add_register(arch_register_class_t *cls, int index, const char *name);
/**
* Add an immediate to the instruction set architecture.
* @param isa The isa.
* @param name The name of the immediate.
* @param mode The mode of the immediate.
* @return The immediate.
*/
arch_immediate_t *arch_add_immediate(arch_isa_t *isa, const char *name, ir_mode *mode);
/**
* Add an instruction format to an isa.
* @param isa The isa.
* @param name The name of the instruction format.
* @param n_in The number of in operands.
* @param n_out The number of out operands.
* @return The format.
*/
arch_insn_format_t *arch_add_insn_format(arch_isa_t *isa, const char *name, int n_in, int n_out);
/**
* Add a register set as an operand type.
* @param fmt The instruction format whose operand is to be set.
* @param pos The position of the operand. Note that input operands are
* numbered from 0 to n and output operands from -1 to -m.
* @param set The register set.
* @return The corresponding operand type.
*/
arch_operand_t *arch_add_operand_register_set(arch_insn_format_t *fmt,
int pos, const arch_register_set_t *set);
arch_operand_t *arch_add_operand_callback(arch_insn_format_t *fmt,
int pos, arch_register_callback_t *cb);
arch_operand_t *arch_add_operand_immediate(arch_insn_format_t *fmt,
int pos, const arch_immediate_t *imm);
/**
* Add an instruction to the isa.
* @param fmt The instructon format.
* @param name The name of the instruction.
*/
arch_insn_t *arch_add_insn(arch_insn_format_t *fmt, const char *name);
/**
* Find an instruction format.
* @param isa The isa.
* @param name The name of the instruction format.
* @return The instruction format, if it was added before, or NULL if it
* is unknown.
*/
arch_insn_format_t *arch_find_insn_format(arch_isa_t *isa, const char *name);
/**
* Find an isa.
* @param name The name of the isa.
* @return The isa if it has been added, or NULl if it is unknwon.
*/
arch_isa_t *arch_find_isa(const char *name);
/**
* Find a register class of an isa.
* @param isa The isa.
* @param name The name of the register class.
* @return The register class, if it has been added, NULL if it is
* unknown.
*/
arch_register_class_t *arch_find_register_class(arch_isa_t *isa, const char *name);
/**
* Get the register set for a register class.
* Each register class possesses a set containing all registers known in
* the class.
* @param cls The class.
* @return The register set for the register class.
*/
arch_register_set_t *arch_get_register_set_for_class(arch_register_class_t *cls);
#endif
/*
The fields have following meaning:
1) Name of the object. This used to ## it to some pre- or suffix.
2) Boolean flag. If 1, the object shall be listed in a list whose
head is in the isa. This is useful, since we can generically
create lists of register classes, formats and so on.
*/
ARCH_OBJ(enum, 1)
ARCH_OBJ(enum_member, 0)
ARCH_OBJ(register, 0)
ARCH_OBJ(register_class, 1)
ARCH_OBJ(register_set, 1)
ARCH_OBJ(immediate, 0)
ARCH_OBJ(operand, 0)
ARCH_OBJ(insn_format, 1)
ARCH_OBJ(insn, 0)
ARCH_OBJ(isa, 0)
#ifndef _FIRM_BEARCH_T_H
#define _FIRM_BEARCH_T_H
#include "firm_config.h"
#include "irop_t.h"
#include "irnode_t.h"
#include "irmode_t.h"
#include "hashptr.h"
#include "fourcc.h"
#include "set.h"
#include "list.h"
#include "ident.h"
#include "bearch.h"
#define ARCH_IRN_FOURCC FOURCC('A', 'R', 'C', 'H')
/**
* Flags for registers.
*/
enum {
/**
* The register is invariant concerning writes.
* Examples are the 0 registers in RISC architectures.
*/
REG_WRITE_INVARIAT = 1
} arch_register_flags_t;
typedef enum {
#define ARCH_OBJ(x,list) arch_kind_##x,
#include "bearch_obj.def"
#undef ARCH_OBJ
arch_kind_last
} arch_kind_t;
/**
* A header which each of the arch structs should posess.
*/
typedef struct {
arch_kind_t kind;
arch_isa_t *isa;
const char *name;
struct list_head list;
unsigned is_new : 1;
} arch_header_t;
/**
* Get the architecture an arch object belongs to.
* @param obj The object.
* @return The architecture it belongs to.
*/
static INLINE arch_isa_t *arch_obj_get_isa(const void *obj)
{
return ((const arch_header_t *) obj)->isa;
}
typedef enum _arch_register_flag_t {
arch_register_flag_none,
arch_register_flag_caller_saved, /**< The register must be saved by the caller
upon a function call. It thus can be overwritten
in the called function. */
arch_register_flag_callee_saved, /**< The register must be saved by the called function,
it thus survives a function call. */
arch_register_flag_ignore /**< Do not consider this register when allocating. */
} arch_register_flag_t;
/**
* A register.
*/
struct _arch_register_t {
arch_header_t header;
int index; /**< The index of the register in the class. */
const arch_register_class_t *reg_class; /**< The class the register belongs to. */
arch_register_flag_t flags; /**< Flags describing several properties of
the register. */
};
/**
* A (sub-) set of registers.
*/
struct _arch_register_set_t {
arch_header_t header;
const struct _arch_register_class_t *reg_class; /**< The register class for this set. */
unsigned comprises_full_class : 1; /**< True, if all registers of the class
are contained in this set. */
int regs[1]; /**< An array containing 0/1 at place i
whether the register with index i is
in the set or not. */
};
static INLINE int _arch_register_in_set(const arch_register_set_t *set, const arch_register_t *reg)
{
if(reg->reg_class != set->reg_class)
return 0;
return set->regs[reg->index];
}
/**
* A class of registers.
* Like general purpose or floating point.
*/
struct _arch_register_class_t {
arch_header_t header;
struct list_head list; /**< list head to list up in the list of all
register classes in an isa. */
arch_register_set_t *set; /**< A register set containing all registers
in this class. */
int n_regs; /**< Number of registers in this class. */
arch_register_t *regs[1]; /**< The array of registers. */
};
static INLINE const arch_register_t *_arch_register_for_index(const arch_register_class_t *cls, int idx)
{
assert(0 <= idx && idx <= cls->n_regs);
return cls->regs[idx];
}
/**
* Get the register set for a register class.
* @param cls The register class.
* @return The set containing all registers in the class.
*/
static INLINE arch_register_set_t *_arch_get_register_set_for_class(const arch_register_class_t *cls)
{
return cls->set;
}
/**
* An immediate.
*/
struct _arch_immediate_t {
arch_header_t header;
ir_mode *mode; /**< The mode of the immediate. */
};
/**
* The member of an enum.
*/
struct _arch_enum_member_t {
arch_header_t header; /**< The omnipresent header. */
arch_enum_t *enm; /**< The enum, this member belongs to. */
};
/**
* An enumeration operand type.
*
* Enumeration operand types can be used to describe the variants
* of an instruction, like giving the cases for a compare (gt, lt,
* eq, ...) some other special attributes of an instruction.
*/
struct _arch_enum_t {
arch_header_t header;
int n_members; /**< The number of members in this enum. */
arch_enum_member_t *members[1]; /**< The array of members. */
};
typedef enum _arch_operand_type_t {
arch_operand_type_ir = 0,
arch_operand_type_variadic,
arch_operand_type_symconst,
arch_operand_type_register_set,
arch_operand_type_immediate
} arch_operand_type_t;
/**
* The data for the different flavours of operand types.
*/
typedef union _arch_operand_data_t {
arch_register_callback_t *callback; /**< The set of valid registers is determined
by a callback function. */
const arch_register_set_t *set; /**< The set of valid registers is directly
given. Note, that if an insn has no constraints,
the set comprises all registers in the
register class. */
const arch_immediate_t *imm; /**< If the operand is an immediate
operand, this describes the kind of
immediate. */
const arch_enum_t *enm; /**< Some enumeration value. */
} arch_operand_data_t;