+ {
+ mark_type (from_type, FULL_ESCAPE);
+ cast = CT_TO_NON_INTER;
+ }
+
+ return cast;
+}
+
+typedef struct cast
+{
+ int type;
+ tree stmt;
+}cast_t;
+
+/* This function is a callback for walk_tree called from
+ is_cast_from_non_pointer. The data->type is set to be:
+
+ 0 - if there is no cast
+ number - the number of casts from non-pointer type
+ -1 - if there is a cast that makes the type to escape
+
+ If data->type = number, then data->stmt will contain the
+ last casting stmt met in traversing. */
+
+static tree
+is_cast_from_non_pointer_1 (tree *tp, int *walk_subtrees, void *data)
+{
+ tree def_stmt = *tp;
+
+
+ if (pointer_set_insert (visited_stmts, def_stmt))
+ {
+ *walk_subtrees = 0;
+ return NULL;
+ }
+
+ switch (TREE_CODE (def_stmt))
+ {
+ case GIMPLE_MODIFY_STMT:
+ {
+ use_operand_p use_p;
+ ssa_op_iter iter;
+ tree lhs = GIMPLE_STMT_OPERAND (def_stmt, 0);
+ tree rhs = GIMPLE_STMT_OPERAND (def_stmt, 1);
+
+ unsigned int cast = look_for_casts (lhs, rhs);
+ /* Check that only one cast happened, and it's of
+ non-pointer type. */
+ if ((cast & CT_FROM_NON_P) == (CT_FROM_NON_P)
+ && (cast & ~(CT_FROM_NON_P)) == 0)
+ {
+ ((cast_t *)data)->stmt = def_stmt;
+ ((cast_t *)data)->type++;
+
+ FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_ALL_USES)
+ {
+ walk_use_def_chains (USE_FROM_PTR (use_p), is_cast_from_non_pointer,
+ data, false);
+ if (((cast_t*)data)->type == -1)
+ return def_stmt;
+ }
+ }
+
+ /* Check that there is no cast, or cast is not harmful. */
+ else if ((cast & CT_NO_CAST) == (CT_NO_CAST)
+ || (cast & CT_DOWN) == (CT_DOWN)
+ || (cast & CT_UP) == (CT_UP)
+ || (cast & CT_USELESS) == (CT_USELESS)
+ || (cast & CT_FROM_MALLOC) == (CT_FROM_MALLOC))
+ {
+ FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_ALL_USES)
+ {
+ walk_use_def_chains (USE_FROM_PTR (use_p), is_cast_from_non_pointer,
+ data, false);
+ if (((cast_t*)data)->type == -1)
+ return def_stmt;
+ }
+ }
+
+ /* The cast is harmful. */
+ else
+ {
+ ((cast_t *)data)->type = -1;
+ return def_stmt;
+ }
+
+ *walk_subtrees = 0;
+ }
+ break;
+
+ default:
+ {
+ *walk_subtrees = 0;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/* This function is a callback for walk_use_def_chains function called
+ from is_array_access_through_pointer_and_index. */
+
+static bool
+is_cast_from_non_pointer (tree var, tree def_stmt, void *data)
+{
+
+ if (!def_stmt || !var)
+ return false;
+
+ if (TREE_CODE (def_stmt) == PHI_NODE)
+ return false;
+
+ if (SSA_NAME_IS_DEFAULT_DEF (var))
+ return false;
+
+ walk_tree (&def_stmt, is_cast_from_non_pointer_1, data, NULL);
+ if (((cast_t*)data)->type == -1)
+ return true;
+
+ return false;
+}
+
+/* When array element a_p[i] is accessed through the pointer a_p
+ and index i, it's translated into the following sequence
+ in gimple:
+
+ i.1_5 = (unsigned int) i_1;
+ D.1605_6 = i.1_5 * 16;
+ D.1606_7 = (struct str_t *) D.1605_6;
+ a_p.2_8 = a_p;
+ D.1608_9 = D.1606_7 + a_p.2_8;
+
+ OP0 and OP1 are of the same pointer types and stand for
+ D.1606_7 and a_p.2_8 or vise versa.
+
+ This function checks that:
+
+ 1. one of OP0 and OP1 (D.1606_7) has passed only one cast from
+ non-pointer type (D.1606_7 = (struct str_t *) D.1605_6;).
+
+ 2. one of OP0 and OP1 which has passed the cast from
+ non-pointer type (D.1606_7), is actually generated by multiplication of
+ index by size of type to which both OP0 and OP1 point to
+ (in this case D.1605_6 = i.1_5 * 16; ).
+
+ 3. an address of def of the var to which was made cast (D.1605_6)
+ was not taken.(How can it happen?)
+
+ The following items are checked implicitly by the end of algorithm:
+
+ 4. one of OP0 and OP1 (a_p.2_8) have never been cast
+ (because if it was cast to pointer type, its type, that is also
+ the type of OP0 and OP1, will be marked as escaped during
+ analysis of casting stmt (when check_cast() is called
+ from scan_for_refs for this stmt)).
+
+ 5. defs of OP0 and OP1 are not passed into externally visible function
+ (because if they are passed then their type, that is also the type of OP0
+ and OP1, will be marked and escaped during check_call function called from
+ scan_for_refs with call stmt).
+
+ In total, 1-5 guaranty that it's an access to array by pointer and index.
+
+*/
+
+static bool
+is_array_access_through_pointer_and_index (tree op0, tree op1)
+{
+ tree base, offset, offset_cast_stmt;
+ tree before_cast, before_cast_def_stmt;
+ cast_t op0_cast, op1_cast;
+
+ /* Check 1. */
+
+ /* Init data for walk_use_def_chains function. */
+ op0_cast.type = op1_cast.type = 0;
+ op0_cast.stmt = op1_cast.stmt = NULL;
+
+ visited_stmts = pointer_set_create ();
+ walk_use_def_chains (op0, is_cast_from_non_pointer,(void *)(&op0_cast), false);
+ pointer_set_destroy (visited_stmts);
+
+ visited_stmts = pointer_set_create ();
+ walk_use_def_chains (op1, is_cast_from_non_pointer,(void *)(&op1_cast), false);
+ pointer_set_destroy (visited_stmts);
+
+ if (op0_cast.type == 1 && op1_cast.type == 0)
+ {
+ base = op1;
+ offset = op0;
+ offset_cast_stmt = op0_cast.stmt;
+ }
+ else if (op0_cast.type == 0 && op1_cast.type == 1)
+ {
+ base = op0;
+ offset = op1;
+ offset_cast_stmt = op1_cast.stmt;
+ }
+ else
+ return false;
+
+ /* Check 2.
+ offset_cast_stmt is of the form:
+ D.1606_7 = (struct str_t *) D.1605_6; */
+
+ before_cast = SINGLE_SSA_TREE_OPERAND (offset_cast_stmt, SSA_OP_USE);
+ if (!before_cast)
+ return false;
+
+ if (SSA_NAME_IS_DEFAULT_DEF(before_cast))
+ return false;
+
+ before_cast_def_stmt = SSA_NAME_DEF_STMT (before_cast);
+ if (!before_cast_def_stmt)
+ return false;
+
+ /* before_cast_def_stmt should be of the form:
+ D.1605_6 = i.1_5 * 16; */
+
+ if (TREE_CODE (before_cast_def_stmt) == GIMPLE_MODIFY_STMT)
+ {
+ tree lhs = GIMPLE_STMT_OPERAND (before_cast_def_stmt,0);
+ tree rhs = GIMPLE_STMT_OPERAND (before_cast_def_stmt,1);
+
+ /* We expect temporary here. */
+ if (!is_gimple_reg (lhs))
+ return false;
+
+ if (TREE_CODE (rhs) == MULT_EXPR)
+ {
+ tree arg0 = TREE_OPERAND (rhs, 0);
+ tree arg1 = TREE_OPERAND (rhs, 1);
+ tree unit_size =
+ TYPE_SIZE_UNIT (TREE_TYPE (TYPE_MAIN_VARIANT (TREE_TYPE (op0))));
+
+ if (!(CONSTANT_CLASS_P (arg0)
+ && simple_cst_equal (arg0,unit_size))
+ && !(CONSTANT_CLASS_P (arg1)
+ && simple_cst_equal (arg1,unit_size)))
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+
+ /* Check 3.
+ check that address of D.1605_6 was not taken.
+ FIXME: if D.1605_6 is gimple reg than it cannot be addressable. */
+
+ return true;