summaryrefslogtreecommitdiff
path: root/gcc/fortran/frontend-passes.c
diff options
context:
space:
mode:
authortkoenig <tkoenig@138bc75d-0d04-0410-961f-82ee72b054a4>2013-04-28 13:32:59 +0000
committertkoenig <tkoenig@138bc75d-0d04-0410-961f-82ee72b054a4>2013-04-28 13:32:59 +0000
commit6dc982b991282587db23a414e3198e93b6444572 (patch)
tree9dcedc944d204b5d8180eb0caf4e8ac6ac8898cc /gcc/fortran/frontend-passes.c
parentefe25f3e347c31deb867efc4fd09691c6dfb8209 (diff)
downloadgcc-6dc982b991282587db23a414e3198e93b6444572.tar.gz
2013-04-28 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/57071 * frontend-passes (optimize_power): New function. (optimize_op): Use it. 2013-04-28 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/57071 * gfortran.dg/power_3.f90: New test. * gfortran.dg/power_4.f90: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@198369 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fortran/frontend-passes.c')
-rw-r--r--gcc/fortran/frontend-passes.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index 0618aed895a..63efb9f919c 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -1091,6 +1091,65 @@ combine_array_constructor (gfc_expr *e)
return true;
}
+/* Change (-1)**k into 1-ishift(iand(k,1),1) and
+ 2**k into ishift(1,k) */
+
+static bool
+optimize_power (gfc_expr *e)
+{
+ gfc_expr *op1, *op2;
+ gfc_expr *iand, *ishft;
+
+ if (e->ts.type != BT_INTEGER)
+ return false;
+
+ op1 = e->value.op.op1;
+
+ if (op1 == NULL || op1->expr_type != EXPR_CONSTANT)
+ return false;
+
+ if (mpz_cmp_si (op1->value.integer, -1L) == 0)
+ {
+ gfc_free_expr (op1);
+
+ op2 = e->value.op.op2;
+
+ if (op2 == NULL)
+ return false;
+
+ iand = gfc_build_intrinsic_call (current_ns, GFC_ISYM_IAND,
+ "_internal_iand", e->where, 2, op2,
+ gfc_get_int_expr (e->ts.kind,
+ &e->where, 1));
+
+ ishft = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ISHFT,
+ "_internal_ishft", e->where, 2, iand,
+ gfc_get_int_expr (e->ts.kind,
+ &e->where, 1));
+
+ e->value.op.op = INTRINSIC_MINUS;
+ e->value.op.op1 = gfc_get_int_expr (e->ts.kind, &e->where, 1);
+ e->value.op.op2 = ishft;
+ return true;
+ }
+ else if (mpz_cmp_si (op1->value.integer, 2L) == 0)
+ {
+ gfc_free_expr (op1);
+
+ op2 = e->value.op.op2;
+ if (op2 == NULL)
+ return false;
+
+ ishft = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ISHFT,
+ "_internal_ishft", e->where, 2,
+ gfc_get_int_expr (e->ts.kind,
+ &e->where, 1),
+ op2);
+ *e = *ishft;
+ return true;
+ }
+ return false;
+}
/* Recursive optimization of operators. */
@@ -1152,6 +1211,10 @@ optimize_op (gfc_expr *e)
case INTRINSIC_DIVIDE:
return combine_array_constructor (e) || changed;
+ case INTRINSIC_POWER:
+ return optimize_power (e);
+ break;
+
default:
break;
}