*ping*
Slightly updated patch below, with a better test case as suggested
by Dominique.
OK for trunk?
2013-03-16 Thomas Koenig
PR fortran/45159
* gfortran.h (gfc_dep_difference): Add prototype.
* dependency.c (discard_nops): New function.
(gfc_dep_difference): New function.
(check_section_vs_section): Use gfc_dep_difference
to calculate the difference of starting indices.
* trans-expr.c (gfc_conv_substring): Use
gfc_dep_difference to calculate the length of
substrings where possible.
2013-03-16 Thomas Koenig
PR fortran/45159
* gfortran.dg/string_length_2.f90: New test.
* gfortran.dg/dependency_41.f90: New test.
Index: gfortran.h
===
--- gfortran.h (Revision 196574)
+++ gfortran.h (Arbeitskopie)
@@ -2959,6 +2959,7 @@ gfc_namespace* gfc_build_block_ns (gfc_namespace *
/* dependency.c */
int gfc_dep_compare_functions (gfc_expr *, gfc_expr *, bool);
int gfc_dep_compare_expr (gfc_expr *, gfc_expr *);
+bool gfc_dep_difference (gfc_expr *, gfc_expr *, mpz_t *);
/* check.c */
gfc_try gfc_check_same_strlen (const gfc_expr*, const gfc_expr*, const char*);
Index: dependency.c
===
--- dependency.c (Revision 196574)
+++ dependency.c (Arbeitskopie)
@@ -500,7 +500,270 @@ gfc_dep_compare_expr (gfc_expr *e1, gfc_expr *e2)
}
}
+/* Helper function to look through parens and unary plus. */
+static gfc_expr*
+discard_nops (gfc_expr *e)
+{
+
+ while (e && e->expr_type == EXPR_OP
+ && (e->value.op.op == INTRINSIC_UPLUS
+ || e->value.op.op == INTRINSIC_PARENTHESES))
+e = e->value.op.op1;
+
+ return e;
+}
+/* Return the difference between two expressions. Integer expressions of
+ the form
+
+ X + constant, X - constant and constant + X
+
+ are handled. Return true on success, false on failure. result is assumed
+ to be uninitialized on entry, and will be initialized on success.
+*/
+
+bool
+gfc_dep_difference (gfc_expr *e1, gfc_expr *e2, mpz_t *result)
+{
+ gfc_expr *e1_op1, *e1_op2, *e2_op1, *e2_op2;
+
+ if (e1 == NULL || e2 == NULL)
+return false;
+
+ if (e1->ts.type != BT_INTEGER || e2->ts.type != BT_INTEGER)
+return false;
+
+ e1 = discard_nops (e1);
+ e2 = discard_nops (e2);
+
+ /* Inizialize tentatively, clear if we don't return anything. */
+ mpz_init (*result);
+
+ /* Case 1: c1 - c2 = c1 - c2, trivially. */
+
+ if (e1->expr_type == EXPR_CONSTANT && e2->expr_type == EXPR_CONSTANT)
+{
+ mpz_sub (*result, e1->value.integer, e2->value.integer);
+ return true;
+}
+
+ if (e1->expr_type == EXPR_OP && e1->value.op.op == INTRINSIC_PLUS)
+{
+ e1_op1 = discard_nops (e1->value.op.op1);
+ e1_op2 = discard_nops (e1->value.op.op2);
+
+ /* Case 2: (X + c1) - X = c1. */
+ if (e1_op2->expr_type == EXPR_CONSTANT
+ && gfc_dep_compare_expr (e1_op1, e2) == 0)
+ {
+ mpz_set (*result, e1_op2->value.integer);
+ return true;
+ }
+
+ /* Case 3: (c1 + X) - X = c1. */
+ if (e1_op1->expr_type == EXPR_CONSTANT
+ && gfc_dep_compare_expr (e1_op2, e2) == 0)
+ {
+ mpz_set (*result, e1_op1->value.integer);
+ return true;
+ }
+
+ if (e2->expr_type == EXPR_OP && e2->value.op.op == INTRINSIC_PLUS)
+ {
+ e2_op1 = discard_nops (e2->value.op.op1);
+ e2_op2 = discard_nops (e2->value.op.op2);
+
+ if (e1_op2->expr_type == EXPR_CONSTANT)
+ {
+ /* Case 4: X + c1 - (X + c2) = c1 - c2. */
+ if (e2_op2->expr_type == EXPR_CONSTANT
+ && gfc_dep_compare_expr (e1_op1, e2_op1) == 0)
+ {
+ mpz_sub (*result, e1_op2->value.integer,
+ e2_op2->value.integer);
+ return true;
+ }
+ /* Case 5: X + c1 - (c2 + X) = c1 - c2. */
+ if (e2_op1->expr_type == EXPR_CONSTANT
+ && gfc_dep_compare_expr (e1_op1, e2_op2) == 0)
+ {
+ mpz_sub (*result, e1_op2->value.integer,
+ e2_op1->value.integer);
+ return true;
+ }
+ }
+ else if (e1_op1->expr_type == EXPR_CONSTANT)
+ {
+ /* Case 6: c1 + X - (X + c2) = c1 - c2. */
+ if (e2_op2->expr_type == EXPR_CONSTANT
+ && gfc_dep_compare_expr (e1_op2, e2_op1) == 0)
+ {
+ mpz_sub (*result, e1_op1->value.integer,
+ e2_op2->value.integer);
+ return true;
+ }
+ /* Case 7: c1 + X - (c2 + X) = c1 - c2. */
+ if (e2_op1->expr_type == EXPR_CONSTANT
+ && gfc_dep_compare_expr (e1_op2, e2_op2) == 0)
+ {
+ mpz_sub (*result, e1_op1->value.integer,
+ e2_op1->value.integer);
+ return true;
+ }
+ }
+ }
+
+ if (e2->expr_type == EXPR_OP && e2->value.op.op == INTRINSIC_MINUS)
+ {
+ e2_op1 = discard_nops (e2->value.op.op1);
+ e2_op2 = discard_nops (e2->value.op.op2);
+
+ if (e1_op2->expr_type == EXPR_CONSTANT)
+ {
+ /* Case 8: X + c1 - (X - c2) = c1 + c2. */
+ if (e2_op2->expr_type == EXPR_CONSTANT
+ && gfc_dep_compare_expr (e1_op1, e2_op1) ==