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

types for constants (optional)

type field for nodes for analyses
simple type analyses

[r1784]
parent ae95c7e0
* 29.8.03 Goetz
Cast: irsimpletype: implement type analyses for one node. Test the
effort of that analyses. Add optimization to iropt that removes
Cast nodes.
* 22.8.2003 Goetz
Firm const nodes should have a type.
In jack all nodes are typed now, except the Const nodes. Only const from
......
......@@ -15,13 +15,13 @@ srcdir = @srcdir@
topdir = ../..
subdir := ir/ana
INSTALL_HEADERS = irouts.h irdom.h cgana.h irloop.h
INSTALL_HEADERS = irouts.h irdom.h cgana.h irloop.h irtypeinfo.h irsimpletype.h
SOURCES = $(INSTALL_HEADERS)
SOURCES += Makefile.in \
irouts.c irdom_t.h irdom.c cgana.c \
irloop_t.h irbackedge.c irbackedge_t.h irscc.c
irloop_t.h irbackedge.c irbackedge_t.h irscc.c irtypeinfo.c irsimpletype.c
include $(topdir)/MakeRules
......
......@@ -110,10 +110,10 @@ loop_element get_loop_element (ir_loop *loop, int pos);
void construct_backedges(ir_graph *irg);
/** Constructs backedges for all irgs in interprocedural view. All
loops in the graph will be marked as such, not only realizeable
loops and recursions in the program. E.g., if the same funcion is
called twice, there is a loop between the first funcion return and
the second call. */
loops in the graph will be marked as such, not only realizeable
loops and recursions in the program. E.g., if the same funcion is
called twice, there is a loop between the first funcion return and
the second call. */
void construct_ip_backedges(void);
#endif /* _IRLOOP_H_ */
/**
*
* @file irsimpeltype.c
*
* Project: libFIRM
* File name: ir/ana/irsimpletype.c
* Purpose: Run most simple type analyses.
* Author: Goetz Lindenmaier
* Modified by:
* Created: 22.8.2003
* CVS-ID: $Id$
* Copyright: (c) 2003 Universitt Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*
*
* We compute type information for each node. It is derived from the
* types of the origines of values, e.g. parameter types can be derived
* from the method type.
* The type information so far is saved in the link field.
*
*/
# include "irtypeinfo.h"
# include "irsimpletype.h"
# include "irprog.h"
# include "irgwalk.h"
# include "ident.h"
#define VERBOSE_UNKNOWN_TYPE(s) printf s
static type *phi_cycle_type = NULL;
/* ------------ Building and Removing the type information ----------- */
/* init type link field so that types point to their pointers. */
void precompute_pointer_types(void) {
int i;
set_type_link(unknown_type, unknown_type);
set_type_link(none_type, unknown_type);
for (i = 0; i < get_irp_n_types(); ++i)
set_type_link(get_irp_type(i), (void *)unknown_type);
for (i = get_irp_n_types()-1; i>=0; --i) {
type *tp = get_irp_type(i);
if (is_pointer_type(tp))
set_type_link(get_pointer_points_to_type(tp), (void *)tp);
}
}
/* Store pointer in link to speed up search of pointer type. */
static type *find_pointer_type_to (type *tp) {
return (type *)get_type_link(tp);
}
static type* compute_irn_type(ir_node *n);
static type *find_type_for_Proj(ir_node *n) {
type *tp;
ir_node *pred = get_Proj_pred(n);
ir_mode *m = get_irn_mode(n);
if (m == mode_T ||
m == mode_BB ||
m == mode_X ||
m == mode_M ||
m == mode_b )
return none_type;
switch(get_irn_opcode(pred)) {
case iro_Proj: {
/* Deal with Start / Call here: we need to know the Proj Nr. */
assert(get_irn_mode(pred) == mode_T);
ir_node *pred_pred = get_Proj_pred(pred);
if (get_irn_op(pred_pred) == op_Start) {
type *mtp = get_entity_type(get_irg_ent(get_Start_irg(pred_pred)));
tp = get_method_param_type(mtp, get_Proj_proj(n));
} else if (get_irn_op(pred_pred) == op_Call) {
type *mtp = get_Call_type(pred_pred);
tp = get_method_res_type(mtp, get_Proj_proj(n));
} else {
VERBOSE_UNKNOWN_TYPE(("Proj %ld from Proj from ??: unknown type\n", get_irn_node_nr(n)));
tp = unknown_type;
}
} break;
case iro_Start: {
/* globals and frame pointer */
if (get_Proj_proj(n) == pns_frame_base)
tp = find_pointer_type_to(get_irg_frame_type(get_Start_irg(pred)));
else if (get_Proj_proj(n) == pns_globals)
tp = find_pointer_type_to(get_glob_type());
else if (get_Proj_proj(n) == pns_value_arg_base) {
VERBOSE_UNKNOWN_TYPE(("Value arg base proj %ld from Start: unknown type\n", get_irn_node_nr(n)));
tp = unknown_type; //find_pointer_type_to(get....(get_entity_type(get_irg_ent(get_Start_irg(pred)))));
} else {
VERBOSE_UNKNOWN_TYPE(("Proj %ld %ld from Start: unknown type\n", get_Proj_proj(n), get_irn_node_nr(n)));
tp = unknown_type;
}
} break;
case iro_Call: {
/* value args pointer */
if (get_Proj_proj(n) == pncl_value_res_base) {
VERBOSE_UNKNOWN_TYPE(("Value res base Proj %ld from Call: unknown type\n", get_irn_node_nr(n)));
tp = unknown_type; //find_pointer_type_to(get....get_Call_type(pred));
} else {
VERBOSE_UNKNOWN_TYPE(("Proj %ld %ld from Call: unknown type\n", get_Proj_proj(n), get_irn_node_nr(n)));
tp = unknown_type;
}
} break;
default:
tp = compute_irn_type(pred);
}
return tp;
}
static type *find_type_for_node(ir_node *n) {
type *tp = NULL;
type *tp1 = NULL, *tp2 = NULL;
ir_node *a = NULL, *b = NULL;
//DDMN(n);
if (is_unop(n)) {
a = get_unop_op(n);
tp1 = compute_irn_type(a);
}
if (is_binop(n)) {
a = get_binop_left(n);
b = get_binop_right(n);
tp1 = compute_irn_type(a);
tp2 = compute_irn_type(b);
}
switch(get_irn_opcode(n)) {
case iro_InstOf: {
assert(0 && "op_InstOf not supported");
} break;
/* has no type */
case iro_Block:
case iro_Start:
case iro_End:
case iro_Jmp:
case iro_Cond:
case iro_Return:
case iro_Raise:
case iro_Call:
case iro_Cmp:
case iro_Store:
case iro_Free:
case iro_Sync:
case iro_Tuple:
case iro_Bad:
case iro_Break:
case iro_CallBegin:
case iro_EndReg:
case iro_EndExcept:
tp = none_type; break;
/* compute the type */
case iro_Const: tp = get_Const_type(n); break;
case iro_SymConst:
tp = unknown_type; break;
case iro_Sel:
tp = find_pointer_type_to(get_entity_type(get_Sel_entity(n))); break;
/* assymetric binops */
case iro_Shl:
case iro_Shr:
case iro_Shrs:
case iro_Rot:
tp = tp1; break;
case iro_Cast:
tp = get_Cast_type(n); break;
case iro_Phi: {
int i;
int n_preds = get_Phi_n_preds(n);
if (n_preds == 0) {tp = none_type; break; }
/* initialize this Phi */
set_irn_type(n, phi_cycle_type);
/* find a first real type */
for (i = 0; i < n_preds; ++i) {
tp1 = compute_irn_type(get_Phi_pred(n, i));
assert(tp1 != initial_type);
if ((tp1 != phi_cycle_type) && (tp1 != none_type))
break;
}
/* find a second real type */
tp2 = tp1;
for (; (i < n_preds); ++i) {
tp2 = compute_irn_type(get_Phi_pred(n, i));
if ((tp2 == phi_cycle_type) || (tp2 == none_type)) {
tp2 = tp1;
continue;
}
if (tp2 != tp1) break;
}
//printf("Types in Phi %s and %s \n", get_type_name(tp1), get_type_name(tp2));
if (tp1 == tp2) { tp = tp1; break; }
VERBOSE_UNKNOWN_TYPE(("Phi %ld with two different types: %s, %s: unknown type.\n", get_irn_node_nr(n),
get_type_name(tp1), get_type_name(tp2)));
tp = unknown_type;
} break;
case iro_Load: {
ir_node *a = get_Load_ptr(n);
if (get_irn_op(a) == op_Sel)
tp = get_entity_type(get_Sel_entity(a));
else if ((get_irn_op(a) == op_Const) &&
(tarval_is_entity(get_Const_tarval(a))))
tp = get_entity_type(tarval_to_entity(get_Const_tarval(a)));
else if (is_pointer_type(compute_irn_type(a)))
tp = get_pointer_points_to_type(get_irn_type(a));
else {
VERBOSE_UNKNOWN_TYPE(("Load %ld with typeless address. result: unknown type\n", get_irn_node_nr(n)));
tp = unknown_type;
}
} break;
case iro_Alloc:
tp = find_pointer_type_to(get_Alloc_type(n)); break;
case iro_Proj:
tp = find_type_for_Proj(n); break;
case iro_Id:
tp = compute_irn_type(get_Id_pred(n)); break;
case iro_Unknown:
tp = unknown_type; break;
case iro_Filter:
assert(0 && "Filter not implemented"); break;
/* catch special cases with fallthrough to binop/unop cases in default. */
case iro_Sub: {
if (mode_is_int(get_irn_mode(n)) &&
mode_is_reference(get_irn_mode(a)) &&
mode_is_reference(get_irn_mode(b)) ) {
VERBOSE_UNKNOWN_TYPE(("Sub %ld ptr - ptr = int: unknown type\n", get_irn_node_nr(n)));
tp = unknown_type; break;
}
} /* fall through to Add. */
case iro_Add: {
if (mode_is_reference(get_irn_mode(n)) &&
mode_is_reference(get_irn_mode(a)) &&
mode_is_int(get_irn_mode(b)) ) {
tp = tp1; break;
}
if (mode_is_reference(get_irn_mode(n)) &&
mode_is_int(get_irn_mode(a)) &&
mode_is_reference(get_irn_mode(b)) ) {
tp = tp2; break;
}
goto default_code;
} break;
case iro_Mul: {
if (get_irn_mode(n) != get_irn_mode(a)) {
VERBOSE_UNKNOWN_TYPE(("Mul %ld int1 * int1 = int2: unknown type\n", get_irn_node_nr(n)));
tp = unknown_type; break;
}
goto default_code;
} break;
default:
default_code: {
if (is_unop(n)) {
/* Is is proper to walk past a Conv??? */
tp = tp1;
break;
}
if (is_binop(n)) {
if (tp1 == tp2) {
tp = tp1;
break;
}
if((tp1 == phi_cycle_type) || (tp2 == phi_cycle_type)) {
tp = phi_cycle_type;
break;
}
VERBOSE_UNKNOWN_TYPE(("Binop %ld with two different types: %s, %s: unknown type \n", get_irn_node_nr(n),
get_type_name(tp1), get_type_name(tp2)));
tp = unknown_type;
break;
}
printf(" not implemented: "); DDMN(n);
} break; /* default */
} /* end switch */
//printf (" found %s ", get_type_name(tp)); DDM;
return tp;
}
static type* compute_irn_type(ir_node *n) {
//DDMN(n);
type *tp = get_irn_type(n);
if ((tp == initial_type)) {
tp = find_type_for_node(n);
set_irn_type(n, tp);
}
//printf (" found %s ", get_type_name(tp)); DDM;
return tp;
}
static void compute_type(ir_node *n, void *env) {
type *tp = get_irn_type(n);
if (tp == phi_cycle_type) {
//printf(" recomputing for phi_cycle_type "); DDMN(n);
set_irn_type(n, initial_type);
}
compute_irn_type(n);
}
static void analyse_irg (ir_graph *irg) {
set_irg_typeinfo_state(irg, irg_typeinfo_consistent);
irg_walk_graph(irg, NULL, compute_type, NULL);
}
static void init_irsimpletype(void) {
init_irtypeinfo();
if (!phi_cycle_type)
phi_cycle_type = new_type_class(new_id_from_str("phi_cycle_type"));
precompute_pointer_types();
}
void simple_analyse_types(void) {
int i;
init_irsimpletype();
for (i = 0; i < get_irp_n_irgs(); i++) {
current_ir_graph = get_irp_irg(i);
analyse_irg(current_ir_graph);
}
}
void free_simple_type_information(void) {
free_irtypeinfo();
if (phi_cycle_type) {
free_type(phi_cycle_type);
phi_cycle_type = NULL;
}
}
/**
*
* @file irsimpeltype.h
*
* Project: libFIRM
* File name: ir/ana/irsimpletype.h
* Purpose: Run most simple type analyses.
* Author: Goetz Lindenmaier
* Modified by:
* Created: 22.8.2003
* CVS-ID: $Id$
* Copyright: (c) 2003 Universität Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*
*
* We compute type information for each node. It is derived from the
* types of the origines of values, e.g. parameter types can be derived
* from the method type.
* The type information so far is saved in the link field.
*
*/
# ifndef _IRSIMPLETYPE_H_
# define _IRSIMPLETYPE_H_
# include "irgraph.h"
# include "irnode.h"
# include "type.h"
/* ------------ Building and Removing the type information ----------- */
/** Computes type information for each node in all ir graphs.
*
* Computes type information for each node. Stores the information in the
* field defined in irtypeinfo.h. Sets typestate in irg to irg_typeinfo_consistent.
*
* Derives the information from nodes/pattarns that give hints about the
* type, as projecting an argument from the Start node. Deletes all previous
* type information.
*
* If a non-pointer type is specified for a pointer value (as the Alloc node does:
* it contains the type allocated, but to type the result we need the type that
* describes a pointer to the allocated type) searches for a corresponding pointer
* type. If several exist, uses one of them. If none exists, uses unknown_type.
*
* Uses the link field of types. Sets this field of each type to point to a
* pointer type that points to the type (Got it? ;-)).
*/
void simple_analyse_types(void);
/** Frees all type information datastructures. Sets the flag in irg to "???". */
void free_simple_type_information(void);
/** Computes type information for a node.
*
* Computes type information for a node. Does not remark this type information
* in the ir. Computes the type information by analysing the predecessors.
* Calls the same basic analyses routine for a node as simple_analyse_types,
* but returns unknown_type for Phi nodes.
* Each call is theoretically O(n).
*
* Not yet implemented, but I guess we want this for iropt, to find the
* type for newly allocated constants.
*/
//type *analyse_irn_type(ir_node *node);
#endif /* _IRSIMPLETYPE_H_ */
/**
*
* @file irtypeinfo.c
*
* Project: libFIRM
* File name: ir/ana/irtypeinfo.c
* Purpose: Data structure to hold type information for nodes.
* Author: Goetz Lindenmaier
* Modified by:
* Created: 28.8.2003
* CVS-ID: $Id$
* Copyright: (c) 2003 Universitt Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*
* Data structure to hold type information for nodes.
*
* This module defines a field "type" of type "type *" for each ir node.
* It defines a flag for irgraphs to mark whether the type info of the
* graph is valid. Further it defines an auxiliary type "initial_type".
*
* The module defines a map that contains pairs (irnode, type). If an irnode
* is not in the map it is assumed to be initialized, i.e., the initialization
* requires no compute time. As firm nodes can not be freed and reallocated
* pointers for nodes are unique (until a call of dead_node_elimination).
*
*/
#include "irtypeinfo.h"
#include <stddef.h>
#include "irgraph_t.h" /* for setting the state flag. */
#include "irprog.h"
#include "pmap.h"
/* ------------ The map. ---------------------------------------------- */
static pmap *type_node_map = NULL;
/* ------------ Auxiliary type. --------------------------------------- */
/* This auxiliary type expresses that a field is uninitialized. The
* variable is set by init_irtypeinfo. The type is freed by
* free_irtypeinfo.
*/
type *initial_type = NULL;
/* ------------ Initializing this module. ----------------------------- */
/* Initializes the type information module.
* Generates a type "initial_type" and sets the type of all nodes to this type.
* Calling set/get_irn_type is invalid before calling init. Requires memory
* in the order of MIN(<calls to set_irn_type>, #irnodes).
*/
void init_irtypeinfo(void) {
int i;
if (!initial_type)
initial_type = new_type_class(new_id_from_str("initial_type"));
/* We need a new, empty map. */
if (type_node_map) pmap_destroy(type_node_map);
type_node_map = pmap_create();
for (i = 0; i < get_irp_n_irgs(); ++i)
set_irg_typeinfo_state(get_irp_irg(i), irg_typeinfo_none);
}
void free_irtypeinfo(void) {
int i;
if (initial_type) {
free_type(initial_type);
initial_type = NULL;
} else
assert(0 && "call init_type_info before freeing");
if (type_node_map) {
pmap_destroy(type_node_map);
type_node_map = NULL;
} else
assert(0 && "call init_type_info before freeing");
for (i = 0; i < get_irp_n_irgs(); ++i)
set_irg_typeinfo_state(get_irp_irg(i), irg_typeinfo_none);
}
/* ------------ Irgraph state handling. ------------------------------- */
void set_irg_typeinfo_state(ir_graph *irg, irg_typeinfo_state s) {
assert(is_ir_graph(irg));
irg->typeinfo_state = s;
}
irg_typeinfo_state get_irg_typeinfo_state(ir_graph *irg) {
assert(is_ir_graph(irg));
return irg->typeinfo_state;
}
/* ------------ Irnode type information. ------------------------------ */
/* These routines only work properly if the ir_graph is in state
* irg_typeinfo_consistent or irg_typeinfo_inconsistent. They
* assume current_ir_graph set properly.
*/
type *get_irn_type(ir_node *n) {
type *res = initial_type;
assert(get_irg_typeinfo_state(current_ir_graph) == irg_typeinfo_consistent ||
get_irg_typeinfo_state(current_ir_graph) == irg_typeinfo_inconsistent );
if (pmap_contains(type_node_map, (void *)n))
res = (type *) pmap_get(type_node_map, (void *)n);
return res;
}
void set_irn_type(ir_node *n, type *tp) {
assert(get_irg_typeinfo_state(current_ir_graph) == irg_typeinfo_consistent ||
get_irg_typeinfo_state(current_ir_graph) == irg_typeinfo_inconsistent );
pmap_insert(type_node_map, (void *)n, (void *)tp);
}
/**
*
* @file irtypeinfo.h
*
* Project: libFIRM
* File name: ir/ana/irtypeinfo.h
* Purpose: Data structure to hold type information for nodes.
* Author: Goetz Lindenmaier
* Modified by:
* Created: 28.8.2003
* CVS-ID: $Id$
* Copyright: (c) 2003 Universität Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*
* Data structure to hold type information for nodes.
*
* This module defines a field "type" of type "type *" for each ir node.
* It defines a flag for irgraphs to mark whether the type info of the
* graph is valid. Further it defines an auxiliary type "init_type".
*
*/
# ifndef _IRTYPEINFO_H_
# define _IRTYPEINFO_H_
# include "irgraph.h"