+/**
+ * Returns an entity if the address ptr points to a constant one.
+ */
+static entity *find_constant_entity(ir_node *ptr)
+{
+ for (;;) {
+ ir_op *op = get_irn_op(ptr);
+
+ if (op == op_SymConst && (get_SymConst_kind(ptr) == symconst_addr_ent)) {
+ return get_SymConst_entity(ptr);
+ }
+ else if (op == op_Sel) {
+ entity *ent = get_Sel_entity(ptr);
+ ir_type *tp = get_entity_owner(ent);
+
+ /* Do not fiddle with polymorphism. */
+ if (is_Class_type(get_entity_owner(ent)) &&
+ ((get_entity_n_overwrites(ent) != 0) ||
+ (get_entity_n_overwrittenby(ent) != 0) ) )
+ return NULL;
+
+ if (variability_constant == get_entity_variability(ent))
+ return ent;
+
+ if (is_Array_type(tp)) {
+ /* check bounds */
+ int i, n;
+
+ for (i = 0, n = get_Sel_n_indexs(ptr); i < n; ++i) {
+ ir_node *bound;
+ tarval *tlower, *tupper;
+ ir_node *index = get_Sel_index(ptr, i);
+ tarval *tv = computed_value(index);
+
+ /* check if the index is constant */
+ if (tv == tarval_bad)
+ return NULL;
+
+ bound = get_array_lower_bound(tp, i);
+ tlower = computed_value(bound);
+ bound = get_array_upper_bound(tp, i);
+ tupper = computed_value(bound);
+
+ if (tlower == tarval_bad || tupper == tarval_bad)
+ return NULL;
+
+ if (tarval_cmp(tv, tlower) & pn_Cmp_Lt)
+ return NULL;
+ if (tarval_cmp(tupper, tv) & pn_Cmp_Lt)
+ return NULL;
+
+ /* ok, bounds check finished */
+ }
+ }
+
+ /* try next */
+ ptr = get_Sel_ptr(ptr);
+ }
+ else
+ return NULL;
+ }
+}
+
+/**
+ * Return the Selection index of a Sel node from dimension n
+ */
+static long get_Sel_array_index_long(ir_node *n, int dim) {
+ ir_node *index = get_Sel_index(n, dim);
+ assert(get_irn_op(index) == op_Const);
+ return get_tarval_long(get_Const_tarval(index));
+}
+
+/**
+ * Returns the accessed component graph path for an
+ * node computing an address.
+ *
+ * @param ptr the node computing the address
+ * @param depth current depth in steps upward from the root
+ * of the address
+ */
+static compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) {
+ compound_graph_path *res = NULL;
+ entity *root, *field;
+ int path_len, pos;
+
+ if (get_irn_op(ptr) == op_SymConst) {
+ /* a SymConst. If the depth is 0, this is an access to a global
+ * entity and we don't need a component path, else we know
+ * at least it's length.
+ */
+ assert(get_SymConst_kind(ptr) == symconst_addr_ent);
+ root = get_SymConst_entity(ptr);
+ res = (depth == 0) ? NULL : new_compound_graph_path(get_entity_type(root), depth);
+ }
+ else {
+ assert(get_irn_op(ptr) == op_Sel);
+ /* it's a Sel, go up until we find the root */
+ res = rec_get_accessed_path(get_Sel_ptr(ptr), depth+1);
+
+ /* fill up the step in the path at the current position */
+ field = get_Sel_entity(ptr);
+ path_len = get_compound_graph_path_length(res);
+ pos = path_len - depth - 1;
+ set_compound_graph_path_node(res, pos, field);
+
+ if (is_Array_type(get_entity_owner(field))) {
+ assert(get_Sel_n_indexs(ptr) == 1 && "multi dim arrays not implemented");
+ set_compound_graph_path_array_index(res, pos, get_Sel_array_index_long(ptr, 0));
+ }
+ }
+ return res;
+}
+
+/** Returns an access path or NULL. The access path is only
+ * valid, if the graph is in phase_high and _no_ address computation is used.
+ */
+static compound_graph_path *get_accessed_path(ir_node *ptr) {
+ return rec_get_accessed_path(ptr, 0);
+}
+