Commit cdd903d8 authored by Michael Beck's avatar Michael Beck
Browse files

added support for Thread local storage

[r7863]
parent 54c4f924
......@@ -818,6 +818,7 @@ static const pns_lookup_t start_lut[] = {
X(X_initial_exec),
X(P_frame_base),
X(P_globals),
X(P_tls),
X(T_args),
X(P_value_arg_base)
#undef X
......
......@@ -900,7 +900,7 @@ static int can_inline(ir_node *call, ir_graph *called_graph)
int inline_method(ir_node *call, ir_graph *called_graph) {
ir_node *pre_call;
ir_node *post_call, *post_bl;
ir_node *in[5];
ir_node *in[pn_Start_max];
ir_node *end, *end_bl;
ir_node **res_pred;
ir_node **cf_pred;
......@@ -983,14 +983,15 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
graph. Both will end up being a tuple. -- */
post_bl = get_nodes_block(call);
set_irg_current_block(current_ir_graph, post_bl);
/* XxMxPxP of Start + parameter of Call */
/* XxMxPxPxPxT of Start + parameter of Call */
in[pn_Start_X_initial_exec] = new_Jmp();
in[pn_Start_M] = get_Call_mem(call);
in[pn_Start_P_frame_base] = get_irg_frame(current_ir_graph);
in[pn_Start_P_globals] = get_irg_globals(current_ir_graph);
in[pn_Start_P_tls] = get_irg_tls(current_ir_graph);
in[pn_Start_T_args] = new_Tuple(get_Call_n_params(call), get_Call_param_arr(call));
/* in[pn_Start_P_value_arg_base] = ??? */
pre_call = new_Tuple(5, in);
pre_call = new_Tuple(pn_Start_max, in);
post_call = call;
/* --
......
......@@ -227,6 +227,7 @@ new_r_ir_graph (entity *ent, int n_loc)
projX = new_Proj(start, mode_X, pn_Start_X_initial_exec);
set_irg_frame (res, new_Proj(start, mode_P_data, pn_Start_P_frame_base));
set_irg_globals (res, new_Proj(start, mode_P_data, pn_Start_P_globals));
set_irg_tls (res, new_Proj(start, mode_P_data, pn_Start_P_tls));
set_irg_args (res, new_Proj(start, mode_T, pn_Start_T_args));
initial_mem = new_Proj(start, mode_M, pn_Start_M);
set_irg_initial_mem(res, initial_mem);
......@@ -244,11 +245,11 @@ new_r_ir_graph (entity *ent, int n_loc)
* Use of this edge is matter of discussion, unresolved. Also possible:
* add_immBlock_pred(res->start_block, res->start_block), but invalid typed.
*/
mature_immBlock (res->current_block);
mature_immBlock(res->current_block);
/*-- Make a block to start with --*/
first_block = new_immBlock();
add_immBlock_pred (first_block, projX);
add_immBlock_pred(first_block, projX);
res->method_execution_frequency = -1;
res->estimated_node_count = 0;
......@@ -258,9 +259,9 @@ new_r_ir_graph (entity *ent, int n_loc)
ir_graph *
new_ir_graph (entity *ent, int n_loc)
new_ir_graph(entity *ent, int n_loc)
{
ir_graph *res = new_r_ir_graph (ent, n_loc);
ir_graph *res = new_r_ir_graph(ent, n_loc);
add_irp_irg(res); /* remember this graph global. */
return res;
}
......@@ -478,6 +479,16 @@ void
_set_irg_globals(irg, node);
}
ir_node *
(get_irg_tls)(const ir_graph *irg) {
return _get_irg_tls(irg);
}
void
(set_irg_tls)(ir_graph *irg, ir_node *node) {
_set_irg_tls(irg, node);
}
ir_node *
(get_irg_initial_mem)(const ir_graph *irg) {
return _get_irg_initial_mem(irg);
......
......@@ -56,22 +56,26 @@
* *frame The ir_node producing the pointer to the stack frame of
* the procedure as output. This is the Proj node on the
* third output of the start node. This output of the start
* node is tagged as pns_frame_base. In FIRM most local
* node is tagged as pns_frame_base. In FIRM most local
* variables are modeled as data flow edges. Static
* allocated arrays can not be represented as data flow
* edges. Therefore FIRM has to represent them in the stack
* frame.
*
* *globals This models a pointer to a space in the memory where
* _all_ global things are held. Select from this pointer
* with a Sel node the pointer to a global variable /
* procedure / compiler known function... .
* _all_ global things are held. Select from this pointer
* with a Sel node the pointer to a global variable /
* procedure / compiler known function... .
*
* *args The ir_node that produces the arguments of the method as
* it's result. This is a Proj node on the fourth output of
* the start node. This output is tagged as pn_Start_T_args.
* *tls This models a pointer to a space in the memory where
* thread local things are held. Select from this pointer
* with a Sel node the pointer to a thread local variable.
*
* *proj_args The proj nodes of the args node.
* *args The ir_node that produces the arguments of the method as
* it's result. This is a Proj node on the fourth output of
* the start node. This output is tagged as pn_Start_T_args.
*
* *proj_args The proj nodes of the args node.
*
* *bad The Bad node is an auxiliary node. It is needed only once,
* so there is this globally reachable node.
......@@ -89,14 +93,14 @@
* Only needed for ir construction.
*
* params/n_loc An int giving the number of local variables in this
* procedure. This is needed for ir construction. Name will
* be changed.
* procedure. This is needed for ir construction. Name will
* be changed.
*
* *value_table This hash table (pset) is used for global value numbering
* for optimizing use in iropt.c.
* for optimizing use in iropt.c.
*
* *Phi_in_stack; a stack needed for automatic Phi construction, needed only
* during ir construction.
* during ir construction.
*
* visited A int used as flag to traverse the ir_graph.
*
......@@ -137,7 +141,7 @@ void set_interprocedural_view(int state);
* procedure:
*
* - The start block containing a start node and Proj nodes for it's
* five results (X, M, P, P, T).
* seven results (X, M, P, P, P, T, P).
* - The end block containing an end node. This block is not matured
* after executing new_ir_graph() as predecessors need to be added to it.
* (Maturing a block means fixing it's number of predecessors.)
......@@ -220,6 +224,11 @@ ir_node *get_irg_globals (const ir_graph *irg);
/** Sets the node that represents the global pointer. */
void set_irg_globals (ir_graph *irg, ir_node *node);
/** Returns the node that represents the tls pointer. */
ir_node *get_irg_tls (const ir_graph *irg);
/** Sets the node that represents the tls pointer. */
void set_irg_tls (ir_graph *irg, ir_node *node);
/** Returns the node that represents the initial memory. */
ir_node *get_irg_initial_mem (const ir_graph *irg);
/** Sets the node that represents the initial memory. */
......
......@@ -64,6 +64,8 @@ enum irg_anchors {
anchor_frame, /**< method's frame */
anchor_globals, /**< pointer to the data segment containing all
globals as well as global procedures. */
anchor_tls, /**< pointer to the thread local storage containing all
thread local data. */
anchor_initial_mem, /**< initial memory of this graph */
anchor_args, /**< methods arguments */
anchor_bad, /**< bad node of this ir_graph, the one and
......@@ -271,6 +273,16 @@ _set_irg_globals(ir_graph *irg, ir_node *node) {
irg->anchors[anchor_globals] = node;
}
static INLINE ir_node *
_get_irg_tls(const ir_graph *irg) {
return irg->anchors[anchor_tls];
}
static INLINE void
_set_irg_tls(ir_graph *irg, ir_node *node) {
irg->anchors[anchor_tls] = node;
}
static INLINE ir_node *
_get_irg_initial_mem(const ir_graph *irg) {
return irg->anchors[anchor_initial_mem];
......@@ -583,6 +595,8 @@ get_idx_irn(ir_graph *irg, unsigned idx) {
#define set_irg_frame(irg, node) _set_irg_frame(irg, node)
#define get_irg_globals(irg) _get_irg_globals(irg)
#define set_irg_globals(irg, node) _set_irg_globals(irg, node)
#define get_irg_tls(irg) _get_irg_tls(irg)
#define set_irg_tls(irg, node) _set_irg_tls(irg, node)
#define get_irg_initial_mem(irg) _get_irg_initial_mem(irg)
#define set_irg_initial_mem(irg, node) _set_irg_initial_mem(irg, node)
#define get_irg_args(irg) _get_irg_args(irg)
......
......@@ -592,8 +592,7 @@ set_nodes_block (ir_node *node, ir_node *block) {
/* Test whether arbitrary node is frame pointer, i.e. Proj(pn_Start_P_frame_base)
* from Start. If so returns frame type, else Null. */
ir_type *is_frame_pointer(ir_node *n) {
if ((get_irn_op(n) == op_Proj) &&
(get_Proj_proj(n) == pn_Start_P_frame_base)) {
if (is_Proj(n) && (get_Proj_proj(n) == pn_Start_P_frame_base)) {
ir_node *start = get_Proj_pred(n);
if (get_irn_op(start) == op_Start) {
return get_irg_frame_type(get_irn_irg(start));
......@@ -605,8 +604,7 @@ ir_type *is_frame_pointer(ir_node *n) {
/* Test whether arbitrary node is globals pointer, i.e. Proj(pn_Start_P_globals)
* from Start. If so returns global type, else Null. */
ir_type *is_globals_pointer(ir_node *n) {
if ((get_irn_op(n) == op_Proj) &&
(get_Proj_proj(n) == pn_Start_P_globals)) {
if (is_Proj(n) && (get_Proj_proj(n) == pn_Start_P_globals)) {
ir_node *start = get_Proj_pred(n);
if (get_irn_op(start) == op_Start) {
return get_glob_type();
......@@ -615,6 +613,18 @@ ir_type *is_globals_pointer(ir_node *n) {
return NULL;
}
/* Test whether arbitrary node is tls pointer, i.e. Proj(pn_Start_P_tls)
* from Start. If so returns tls type, else Null. */
ir_type *is_tls_pointer(ir_node *n) {
if (is_Proj(n) && (get_Proj_proj(n) == pn_Start_P_globals)) {
ir_node *start = get_Proj_pred(n);
if (get_irn_op(start) == op_Start) {
return get_tls_type();
}
}
return NULL;
}
/* Test whether arbitrary node is value arg base, i.e. Proj(pn_Start_P_value_arg_base)
* from Start. If so returns 1, else 0. */
int is_value_arg_pointer(ir_node *n) {
......
......@@ -245,14 +245,16 @@ typedef enum {
pn_Start_M, /**< Projection on the initial memory. */
pn_Start_P_frame_base, /**< Projection on the frame base pointer. */
pn_Start_P_globals, /**< Projection on the pointer to the data segment
containing _all_ global entities. */
containing _all_ global entities. Use for
position independent data/code access. */
pn_Start_P_tls, /**< Projection on the pointer to the thread local store
segment containing _all_thread local variables. */
pn_Start_T_args, /**< Projection on all arguments. */
pn_Start_P_value_arg_base, /**< Pointer to region of compound value arguments as defined by
type of this method. */
pn_Start_max /**< number of projections from a Start */
} pn_Start; /* Projection numbers for Start. */
/** Test whether arbitrary node is frame pointer.
*
* Test whether arbitrary node is frame pointer, i.e. Proj(pn_Start_P_frame_base)
......@@ -265,6 +267,12 @@ ir_type *is_frame_pointer(ir_node *n);
* from Start. If so returns global type, else Null. */
ir_type *is_globals_pointer(ir_node *n);
/** Test whether arbitrary node is tls pointer.
*
* Test whether arbitrary node is tls pointer, i.e. Proj(pn_Start_P_tls)
* from Start. If so returns tls type, else Null. */
ir_type *is_tls_pointer(ir_node *n);
/** Test whether arbitrary node is value arg base.
*
* Test whether arbitrary node is value arg base, i.e. Proj(pn_Start_P_value_arg_base)
......
......@@ -26,7 +26,11 @@
#include "typegmod.h"
#include "irop_t.h"
/** The name of the Global Type. */
#define GLOBAL_TYPE_NAME "GlobalType"
/** The name of the Thread Local STorage Type. */
#define TLS_TYPE_NAME "TLS"
/** The initial name of the irp program. */
#define INITAL_PROG_NAME "no_name_set"
/* A variable from where everything in the ir can be accessed. */
......@@ -39,7 +43,7 @@ ir_prog *get_irp(void) { return irp; }
static ir_prog *new_incomplete_ir_prog (void) {
ir_prog *res;
res = xmalloc (sizeof(*res));
res = xmalloc(sizeof(*res));
memset(res, 0, sizeof(*res));
irp = res;
......@@ -59,13 +63,15 @@ static ir_prog *new_incomplete_ir_prog (void) {
/** Completes an incomplete irprog. */
static ir_prog *complete_ir_prog(ir_prog *irp) {
#define X(s) s, sizeof(s)-1
irp->name = new_id_from_chars(X(INITAL_PROG_NAME));
irp->name = new_id_from_str(INITAL_PROG_NAME);
irp->glob_type = new_type_class(new_id_from_str (GLOBAL_TYPE_NAME));
/* Remove type from type list. Must be treated differently than
irp->glob_type = new_type_class(new_id_from_chars(X(GLOBAL_TYPE_NAME)));
irp->tls_type = new_type_struct(new_id_from_chars(X(TLS_TYPE_NAME)));
/* Remove these types from type list. Must be treated differently than
other types. */
remove_irp_type(irp->glob_type);
remove_irp_type(irp->tls_type);
irp->const_code_irg = new_const_code_irg();
......@@ -99,6 +105,8 @@ ir_prog *new_ir_prog (void) {
void free_ir_prog(void) {
if (irp->glob_type)
free_type(irp->glob_type);
if (irp->tls_type)
free_type(irp->tls_type);
/* @@@ * free_ir_graph(irp->const_code_irg); * ?? End has no in?? */
DEL_ARR_F(irp->graphs);
......@@ -130,6 +138,10 @@ ir_type *(get_glob_type)(void) {
return _get_glob_type();
}
ir_type *(get_tls_type)(void) {
return _get_tls_type();
}
/* Adds irg to the list of ir graphs in irp. */
void add_irp_irg(ir_graph *irg) {
assert (irg != NULL);
......@@ -186,7 +198,7 @@ void set_irp_irg(int pos, ir_graph *irg) {
}
/* Gets the number of graphs _and_ pseudo graphs. */
int get_irp_n_allirgs(void) {
int get_irp_n_allirgs(void) {
/* We can not call get_irp_n_irgs, as we end up in a recursion ... */
return ARR_LEN(irp->graphs) + get_irp_n_pseudo_irgs();
}
......
......@@ -131,10 +131,18 @@ int get_irp_n_allirgs(void);
pseudo graphs). Visits first graphs, then pseudo graphs. */
ir_graph *get_irp_allirg(int pos);
/** Returns the "global" type of the irp. */
/**
* Returns the "global" type of the irp.
* Upon creation this is an empty class type.
*/
ir_type *get_glob_type(void);
/**
* Returns the "thread local storage" type of the irp.
* Upon creation this is an empty struct type.
*/
ir_type *get_tls_type(void);
/** Adds type to the list of types in irp. */
void add_irp_type(ir_type *typ);
......
......@@ -48,8 +48,10 @@ struct ir_prog {
to allocate nodes the represent values
of constant entities. It is not meant as
a procedure. */
ir_type *glob_type; /**< global type. Must be a class as it can
ir_type *glob_type; /**< The global type. Must be a class as it can
have fields and procedures. */
ir_type *tls_type; /**< The thread local storage type. Must be a struct as it can
only have fields. */
ir_type **types; /**< all types in the ir */
ir_mode **modes; /**< all modes in the ir */
ir_op **opcodes; /**< all opcodes in the ir */
......@@ -96,6 +98,12 @@ _get_glob_type(void) {
return irp->glob_type = skip_tid(irp->glob_type);
}
static INLINE ir_type *
_get_tls_type(void) {
assert(irp);
return irp->tls_type = skip_tid(irp->tls_type);
}
static INLINE int
_get_irp_n_irgs(void) {
assert (irp && irp->graphs);
......@@ -181,5 +189,6 @@ void init_irprog_2(void);
#define get_irp_opcode(pos) _get_irp_opcode(pos)
#define get_const_code_irg() _get_const_code_irg()
#define get_glob_type() _get_glob_type()
#define get_tls_type() _get_tls_type()
#endif /* ifndef _FIRM_IR_IRPROG_T_H_ */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment