Commit 5052f2d2 authored by Götz Lindenmaier's avatar Götz Lindenmaier
Browse files

Added support for constant entities. A new example program illustrates

  their use.  Extended dumper routines to dump constant values.

[r287]
parent b4eb108c
10.12.2001 Goetz
Added support for constant entities. A new example program illustrates
their use. Extended dumper routines to dump constant values.
30.11.2001 Goetz
Extendend "comfortable" construction interface by some methods
serving as simple shortcuts.
......
......@@ -47,7 +47,7 @@
/* If this and DEBUG_libfirm are defined irdump uses the nodeid numbers as
labels for the vcg nodes. This makes the vcg graph better readable.
Sometimes it's useful to see the pointer values, though. */
#define NODEID_AS_LABEL 1
#define NODEID_AS_LABEL 0
/* a list of firm kinds */
typedef enum {
......
......@@ -53,6 +53,8 @@
#define ARR_ELT_TYPE_EDGE_ATTR "class: 10 label: \"arr elt tp\" color:green"
#define ARR_ENT_EDGE_ATTR "class: 10 label: \"arr ent\" color: green"
#define ENT_OVERWRITES_EDGE_ATTR "class: 11 label: \"overwrites\" color:red"
#define ENT_VALUE_EDGE_ATTR "label: \"value "
#define ENT_CORR_EDGE_ATTR "label: \"value %d corresponds to \" "
#define TYPE_MEMBER_EDGE_ATTR "class: 12 label: \"member\" color:blue"
......@@ -67,10 +69,16 @@ static FILE *F;
/* A compiler option to turn off edge labels */
int edge_label = 1;
/* A compiler option to turn off dumping values of constant entities */
int const_entities = 1;
/* A global variable to record output of the Bad node. */
int Bad_dumped;
void dump_ir_blocks_nodes (ir_node *n, void *env);
void dump_whole_node (ir_node *n, void* env);
/*******************************************************************/
/* routines to dump information about a single node */
/*******************************************************************/
......@@ -472,6 +480,9 @@ void dump_node2type_edges (ir_node *n, void *env)
assert(n);
switch (get_irn_opcode(n)) {
case iro_Const :
/* @@@ some consts have an entity */
break;
case iro_SymConst:
if ( (get_SymConst_kind(n) == type_tag)
|| (get_SymConst_kind(n) == size)) {
......@@ -511,6 +522,15 @@ void dump_node2type_edges (ir_node *n, void *env)
}
void dump_const_expression(ir_node *value) {
ir_graph *rem = current_ir_graph;
current_ir_graph = get_const_code_irg();
irg_walk(value, dump_ir_blocks_nodes, NULL, get_nodes_Block(value));
set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph) -1);
current_ir_graph = rem;
}
/* dumps a type or entity and it's edges. */
void
dump_type_info (type_or_ent *tore, void *env) {
......@@ -525,18 +545,55 @@ dump_type_info (type_or_ent *tore, void *env) {
case k_entity:
{
entity *ent = (entity *)tore;
ir_node *value;
/* The node */
xfprintf (F, "\"ent %I\" " ENTITY_NODE_ATTR , get_entity_ident(ent));
if(dynamic_allocated == get_entity_allocation(ent))
xfprintf (F, " info1:\"dynamic allocated\"}\n");
xfprintf (F, " info1:\"dynamic allocated\n");
else
xfprintf (F, " info1:\"static allocated\"}\n");
xfprintf (F, "nearedge: { sourcename: \"%p\" targetname: \"%p\" "
ENT_OWN_EDGE_ATTR "}\n", tore, get_entity_owner(ent));
xfprintf (F, " info1:\"static allocated\n");
switch (get_entity_visibility(ent)) {
case local: fprintf (F, "local\n"); break;
case external_visible: fprintf (F, "external_visible\n"); break;
case external_allocated: fprintf (F, "external_allocate\nd");break;
}
switch (get_entity_variability(ent)) {
case uninitialized: fprintf (F, "uninitialized");break;
case initialized: fprintf (F, "initialized"); break;
case part_constant: fprintf (F, "part_constant");break;
case constant: fprintf (F, "constant"); break;
}
xfprintf(F, "\"}\n");
/* The Edges */
xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
ENT_OWN_EDGE_ATTR "}\n", ent, get_entity_owner(ent));
xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
ENT_TYPE_EDGE_ATTR "}\n", tore, get_entity_type(ent));
ENT_TYPE_EDGE_ATTR "}\n", ent, get_entity_type(ent));
for(i = 0; i < get_entity_n_overwrites(ent); i++)
xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
ENT_OVERWRITES_EDGE_ATTR "}\n", tore, get_entity_overwrites(ent, i));
ENT_OVERWRITES_EDGE_ATTR "}\n", ent, get_entity_overwrites(ent, i));
/* attached subgraphs */
if (const_entities && (get_entity_variability(ent) != uninitialized)) {
if (is_atomic_entity(ent)) {
value = get_atomic_ent_value(ent);
xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"", ent);
PRINT_NODEID(value);
fprintf(F, "\" " ENT_VALUE_EDGE_ATTR "\"}\n");
dump_const_expression(value);
}
if (is_compound_entity(ent)) {
for (i = 0; i < get_compound_ent_n_values(ent); i++) {
value = get_compound_ent_value(ent, i);
xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"", ent);
PRINT_NODEID(value);
fprintf(F, "\" " ENT_VALUE_EDGE_ATTR " %d \"}\n", i);
dump_const_expression(value);
xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
ENT_CORR_EDGE_ATTR "}\n", ent,
get_compound_ent_value_member(ent, i), i);
}
}
}
} break;
case k_type:
{
......@@ -902,6 +959,11 @@ dump_type_graph (ir_graph *irg)
/* walk over the blocks in the graph */
type_walk_irg(irg, dump_type_info, NULL, NULL);
/* The walker for the const code can be called several times for the
same (sub) experssion. So that no nodes are dumped several times
we decrease the visited flag of the corresponding graph after each
walk. So now increase it finally. */
inc_irg_visited(get_const_code_irg());
vcg_close();
current_ir_graph = rem;
......@@ -917,6 +979,7 @@ dump_all_types (void)
{
vcg_open_name ("All_types");
type_walk(dump_type_info, NULL, NULL);
inc_irg_visited(get_const_code_irg());
vcg_close();
}
......@@ -938,6 +1001,7 @@ dump_ir_graph_w_types (ir_graph *irg)
irg_walk(irg->end, dump_whole_node, NULL, NULL);
/* dump type info */
type_walk_irg(irg, dump_type_info, NULL, NULL);
inc_irg_visited(get_const_code_irg());
/* dump edges from graph to type info */
irg_walk(irg->end, dump_node2type_edges, NULL, NULL);
......@@ -958,6 +1022,7 @@ dump_ir_block_graph_w_types (ir_graph *irg)
dump_ir_block_graph_2(irg);
/* dump type info */
type_walk_irg(irg, dump_type_info, NULL, NULL);
inc_irg_visited(get_const_code_irg());
/* dump edges from graph to type info */
irg_walk(irg->end, dump_node2type_edges, NULL, NULL);
......@@ -986,3 +1051,7 @@ void dump_all_ir_graphs (void dump_graph(ir_graph*)) {
void turn_of_edge_labels() {
edge_label = 0;
}
void dump_constant_entity_values() {
const_entities = 0;
}
......@@ -238,4 +238,23 @@ void dump_all_ir_graphs (void dump_graph(ir_graph*));
void turn_of_edge_labels();
/****m* irdump/dump_constant_entity_values
*
* NAME
* dump_constant_entity_values
* SYNOPSIS
* void dump_constant_entity_values()
* FUNCTION
* Turns off dumping the values of constant entities. Maked type graphs
* better readable.
* INPUTS
* No inputs
* RESULT
* SEE ALSO
*
***
*/
void dump_constant_entity_values();
# endif /* _IRDUMP_H_ */
......@@ -115,6 +115,50 @@ new_ir_graph (entity *ent, int n_loc)
return res;
}
/* Make a rudimentary ir graph for the constant code.
Must look like a correct irg, spare everything else. */
ir_graph *new_const_code_irg() {
ir_graph *res;
ir_node *projX;
res = (ir_graph *) malloc (sizeof (ir_graph));
current_ir_graph = res;
res->n_loc = 1; /* Only the memory. */
res->visited = 0; /* visited flag, for the ir walker */
res->block_visited=0; /* visited flag, for the 'block'-walker */
#if USE_EXPICIT_PHI_IN_STACK
res->Phi_in_stack = NULL;
#endif
res->obst = (struct obstack *) xmalloc (sizeof (struct obstack));
obstack_init (res->obst);
res->value_table = new_identities (); /* value table for global value
numbering for optimizing use in
iropt.c */
res->ent = NULL;
res->frame_type = NULL;
res->start_block = new_immBlock ();
res->end_block = new_immBlock ();
res->end = new_End ();
mature_block(get_cur_block());
res->bad = new_ir_node (res, res->start_block, op_Bad, mode_T, 0, NULL);
res->start = new_Start ();
/* Proj results of start node */
projX = new_Proj (res->start, mode_X, pns_initial_exec);
set_store (new_Proj (res->start, mode_M, pns_global_store));
add_in_edge(res->start_block, projX);
mature_block (res->current_block);
add_in_edge (new_immBlock (), projX);
mature_block(get_cur_block());
/* Set the visited flag high enough that the block will never be visited. */
set_irn_visited(get_cur_block(), -1);
set_Block_block_visited(get_cur_block(), -1);
set_Block_block_visited(res->start_block, -1);
return res;
}
/* Frees the passed irgraph.
Deallocates all nodes in this graph and the ir_graph structure.
Sets the field irgraph in the corresponding entity to NULL.
......
......@@ -49,4 +49,10 @@ struct ir_graph {
unsigned long block_visited; /* same as visited, for a
complete block */
};
/* Make a rudimentary ir graph for the constant code.
Must look like a correct irg, spare everything else. */
ir_graph *new_const_code_irg();
# endif /* _IRGRAPH_T_H_ */
......@@ -491,6 +491,8 @@ ir_node *get_fragile_op_mem(ir_node *node);
get_irn_node_nr(X))
#define DDMSG3(X) printf("%s(l.%i) %s: %p\n", __FUNCTION__, __LINE__, \
print_firm_kind(X), (X))
#define DDMSG4(X) printf("%s(l.%i) %s %s: %p\n", __FUNCTION__, __LINE__, \
get_type_tpop_name(X), get_type_name(X), (X))
#endif
......
......@@ -13,6 +13,7 @@
#endif
# include "irprog_t.h"
# include "irgraph_t.h"
# include "array.h"
# include "obst.h"
# include "typegmod.h"
......@@ -42,6 +43,8 @@ ir_prog *new_ir_prog (void) {
strlen(GLOBAL_TYPE_NAME)));
add_irp_type((type *)res->glob_type);
res->const_code_irg = new_const_code_irg();
#ifdef DEBUG_libfirm
res->max_node_nr = 1;
#endif
......@@ -142,3 +145,8 @@ int get_irp_new_node_nr() {
return irp->max_node_nr - 1;
}
#endif
ir_graph *get_const_code_irg()
{
return irp->const_code_irg;
}
......@@ -91,4 +91,17 @@ int get_irp_new_node_nr();
#endif
/*****/
/***p* irprog/get_const_code_irg
*
* NAME
* get_const_code_irg - Returns an irgraph that only contains constant
* expressions for constant entities.
* SYNOPSIS
* ir_graph *get_const_code_irg();
* NOTE
* Do not use any access function for this graph, do not generate code
* for this graph.
*/
ir_graph *get_const_code_irg();
#endif /* ifndef _IRPROG_H_ */
......@@ -14,8 +14,13 @@ struct ir_prog {
type *glob_type; /* global type. Must be a class as it can
have fields and procedures. */
type **types; /* all types in the ir */
ir_graph *const_code_irg; /* This ir graph gives the proper environment
to allocate nodes the represent values
of constant entities. It is not meant as
a procedure. */
/*struct obstack *obst; * @@@ Should we place all types and
entities on an obstack, too? */
#ifdef DEBUG_libfirm
long max_node_nr; /* to generate unique numbers for nodes. */
#endif
......
......@@ -17,6 +17,9 @@
# include "mangle.h"
# include "typegmod_t.h"
# include "array.h"
/* All this is needed to build the constant node for methods: */
# include "irprog.h"
# include "ircons.h"
/*******************************************************************/
/** general **/
......@@ -54,6 +57,7 @@ entity *
new_entity (type *owner, ident *name, type *type)
{
entity *res;
ir_graph *rem;
res = (entity *) malloc (sizeof (entity));
res->kind = k_entity;
......@@ -63,6 +67,15 @@ new_entity (type *owner, ident *name, type *type)
res->type = type;
res->allocation = dynamic_allocated;
res->visibility = local;
if (is_method_type(type)) {
res->variability = constant;
rem = current_ir_graph;
current_ir_graph = get_const_code_irg();
res->value = new_Const(mode_p, tarval_p_from_entity(res));
current_ir_graph = rem;
} else {
res->variability = uninitialized;
}
res->ld_name = NULL;
res->overwrites = NEW_ARR_F(entity *, 1);
......@@ -197,6 +210,80 @@ set_entity_visibility (entity *ent, ent_visibility vis) {
ent->visibility = vis;
}
inline ent_variability
get_entity_variability (entity *ent) {
return ent->variability;
}
inline void
set_entity_variability (entity *ent, ent_variability var){
if (var == part_constant)
assert(is_class_type(ent->type) || is_struct_type(ent->type));
if ((is_compound_type(ent->type)) &&
(ent->variability == uninitialized) && (var != uninitialized)) {
/* Allocate datastructures for constant values */
ent->values = NEW_ARR_F(ir_node *, 1);
ent->val_ents = NEW_ARR_F(entity *, 1);
}
if ((is_compound_type(ent->type)) &&
(var == uninitialized) && (ent->variability != uninitialized)) {
/* Free datastructures for constant values */
DEL_ARR_F(ent->values);
DEL_ARR_F(ent->val_ents);
}
ent->variability = var;
}
/* Set has no effect for entities of type method. */
inline ir_node *
get_atomic_ent_value(entity *ent) {
assert(ent); assert(is_atomic_entity(ent)); assert((ent->variability != uninitialized));
return ent->value;
}
inline void
set_atomic_ent_value(entity *ent, ir_node *val) {
assert(ent && is_atomic_entity(ent) && (ent->variability != uninitialized));
if (is_method_type(ent->type)) return;
ent->value = val;
}
/* A value of a compound entity is a pair of value and the corresponding member of
the compound. */
inline void
add_compound_ent_value(entity *ent, ir_node *val, entity *member) {
assert(ent && is_compound_entity(ent) && (ent->variability != uninitialized));
ARR_APP1 (ir_node *, ent->values, val);
ARR_APP1 (entity *, ent->val_ents, member);
}
inline int
get_compound_ent_n_values(entity *ent) {
assert(ent && is_compound_entity(ent) && (ent->variability != uninitialized));
return (ARR_LEN (ent->values))-1;
}
inline ir_node *
get_compound_ent_value(entity *ent, int pos) {
assert(ent && is_compound_entity(ent) && (ent->variability != uninitialized));
return ent->values[pos+1];
}
inline entity *
get_compound_ent_value_member(entity *ent, int pos) {
assert(ent && is_compound_entity(ent) && (ent->variability != uninitialized));
return ent->val_ents[pos+1];
}
inline void
set_compound_ent_value(entity *ent, ir_node *val, entity *member, int pos) {
assert(ent && is_compound_entity(ent) && (ent->variability != uninitialized));
ent->values[pos+1] = val;
ent->val_ents[pos+1] = member;
}
inline int
get_entity_offset (entity *ent) {
return ent->offset;
......@@ -258,3 +345,15 @@ set_entity_irg(entity *ent, ir_graph *irg) {
assert (is_method_type(ent->type));
ent->irg = irg;
}
int is_atomic_entity(entity *ent) {
type* t = ent->type;
return (is_primitive_type(t) || is_pointer_type(t) ||
is_enumeration_type(t) || is_method_type(t));
}
int is_compound_entity(entity *ent) {
type* t = ent->type;
return (is_class_type(t) || is_struct_type(t) ||
is_array_type(t) || is_union_type(t));
}
......@@ -83,6 +83,8 @@ typedef struct ir_graph ir_graph;
* @@@ Does this make sense???
* visibility A flag indicating the visibility of this entity (values: local,
* external_visible, external_allocated)
* variability A flag indicating the variability of this entity (values:
* uninitialized, initalized, part_constant, constant)
* offset The offset of the entity within the compound object. Only set
* if IR in the state "@@@" Wie nennen wir den??
* overwrites A list of entities overwritten by this entity. This list is only
......@@ -167,6 +169,33 @@ typedef enum {
ent_visibility get_entity_visibility (entity *ent);
void set_entity_visibility (entity *ent, ent_visibility vis);
/* This enumeration flags the variability of entities. */
typedef enum {
uninitialized, /* The content of the entity is completely unknown. */
initialized, /* After allocation the entity is initalized with the
value given somewhere in the entity. */
part_constant, /* For entities of compound types. Some members of the entity
are constant. The others are uninitialized. Those members
given a value for are constant. */
constant /* The entity is constant. */
} ent_variability;
ent_variability get_entity_variability (entity *ent);
void set_entity_variability (entity *ent, ent_variability var);
/* Set has no effect for entities of type method. */
ir_node * get_atomic_ent_value(entity *ent);
void set_atomic_ent_value(entity *ent, ir_node *val);
/* A value of a compound entity is a pair of value and the corresponding member of
the compound. */
void add_compound_ent_value(entity *ent, ir_node *val, entity *member);
int get_compound_ent_n_values(entity *ent);
ir_node *get_compound_ent_value(entity *ent, int pos);
entity *get_compound_ent_value_member(entity *ent, int pos);
void set_compound_ent_value(entity *ent, ir_node *val, entity *member, int pos);
/* Only set if layout = fixed. */
int get_entity_offset (entity *ent);
void set_entity_offset (entity *ent, int offset);
......@@ -193,6 +222,13 @@ ir_graph *get_entity_irg(entity *ent);
void set_entity_irg(entity *ent, ir_graph *irg);
/* Returns true if the type of the entity is a primitive, pointern
enumeration or method type. */
int is_atomic_entity(entity *ent);
/* Returns true if the type of the entity is a class, structure,
array or union type. */
int is_compound_entity(entity *ent);
/*****/
......
......@@ -54,6 +54,10 @@ struct entity {
entities. */
ent_visibility visibility; /* Specifies visibility to external program
fragments */
ent_variability variability; /* Specifies variability of entities content */
ir_node *value; /* value of atomic entity */
ir_node **values; /* values of compound entities */
entity **val_ents; /* entities corresponding to constant values */
int offset; /* Offset in byte for this entity. Fixed when layout
of owner is determined. */
void *link; /* To store some intermediate information */
......@@ -61,8 +65,8 @@ struct entity {
ir_graph *irg; /* If (type == method_type) this is the corresponding irg.
The ir_graph constructor automatically sets this field.
@@@ Does this go here, or should it be in type_method,
or should Call have an attribute ent?? */
/* Do we need to remember the initializer of fields? */
or should Call have an attribute ent??
Yes, it must be here. */
unsigned long visit; /* visited counter for walks of the type information */
};
......
......@@ -37,6 +37,9 @@
# include "tpop_t.h"
# include "typegmod_t.h"
# include "array.h"
# include "irprog.h"
# include "mangle.h"
# include "tv.h"
/*******************************************************************/
/** TYPE **/
......@@ -529,6 +532,19 @@ int get_array_n_dimensions (type *array) {
assert(array && (array->type_op == type_array));
return array->attr.aa.n_dimensions;
}
void set_array_bounds_int (type *array, int dimension, int lower_bound,
int upper_bound) {
ir_graph *rem;
assert(array && (array->type_op == type_array));
rem = current_ir_graph;
current_ir_graph = get_const_code_irg();
array->attr.aa.lower_bound[dimension] =
new_Const(mode_I, tarval_from_long (mode_I, lower_bound));
array->attr.aa.upper_bound[dimension] =
new_Const(mode_I, tarval_from_long (mode_I, upper_bound));
current_ir_graph = rem;
}
void set_array_bounds (type *array, int dimension, ir_node * lower_bound,
ir_node * upper_bound) {
assert(array && (array->type_op == type_array));
......@@ -679,3 +695,12 @@ bool is_primitive_type (type *primitive) {
assert(primitive);
if (primitive->type_op == type_primitive) return 1; else return 0;
}
int is_atomic_type(type *tp) {
return (is_primitive_type(tp) || is_pointer_type(tp) ||
is_enumeration_type(tp));
}
int is_compound_type(type *tp) {
return (is_class_type(tp) || is_struct_type(tp) ||
is_array_type(tp) || is_union_type(tp));
}
......@@ -381,6 +381,8 @@ void set_union_delim_nameid (type *uni, int pos, ident *id);
* Representation of an array type.
* NOTE
* The array type represents rectangular multi dimensional arrays.
* The constants representing the bounds must be allocated to
* get_const_code_irg() by setting current_ir_graph accordingly.
* ATTRIBUTES
* n_dimensions Number of array dimensions.
* *lower_bound Lower bounds of dimensions. Usually all 0.
......@@ -401,6 +403,9 @@ type *new_type_array (ident *name, int n_dimensions,
/* manipulate private fields of array type */
int get_array_n_dimensions (type *array);
/* Allocates Const nodes of mode_I for the array dimensions */
void set_array_bounds_int (type *array, int dimension, int lower_bound,
int upper_bound);
void set_array_bounds (type *array, int dimension, ir_node *lower_bound,
ir_node *upper_bound);
void set_array_lower_bound (type *array, int dimension, ir_node *lower_bound);
......@@ -486,4 +491,34 @@ type *new_type_primitive (ident *name, ir_mode *mode);
bool is_primitive_type (type *primitive);
/*****/
/****f* type/is_atomic_type
*
* NAME
* is_atomic_type - Checks whether a type is atomic.
* SYNOPSIS
* int is_atomic_type(type *tp);
* INPUTS
* tp - any type
* RESULT
* true if type is primitive, pointer or enumeration
***
*/
int is_atomic_type(type *tp);
/****f* type/is_compound_type
*
* NAME
* is_compound_type - Checks whether a type is compound.
* SYNOPSIS
* int is_compound_type(type *tp)
* INPUTS
* tp - any type