diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-06-26 18:39:06 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-06-26 18:39:06 +0000 |
commit | 21543d4cd558cada630271a0cf3075ad7ce94cbf (patch) | |
tree | 08bdb3f3e0a9d0f71e72bb56d9ddb7b916e7dfeb /gcc/fortran/trans-intrinsic.c | |
parent | ed0bc1ffb674fe93d0df68654b5bb76869f0bc8c (diff) | |
download | gcc-21543d4cd558cada630271a0cf3075ad7ce94cbf.tar.gz |
2013-06-26 Basile Starynkevitch <basile@starynkevitch.net>
{{merged with trunk [4.9] svn rev. 196654-200426}}
MELT branch merged with trunk rev. 200426 using svnmerge.py
[gcc/]
2013-06-26 Basile Starynkevitch <basile@starynkevitch.net>
{{merge with trunk [4.9] svn rev. 196654-200426}}
* melt-runtime.c (melt_val2passflag): TODO_ggc_collect &
TODO_do_not_ggc_collect are conditionalized.
* melt/generated/warmelt-first+03.cc: Manually remove calls to
MELT_TRACE_EXIT_LOCATION macro.
* melt/generated/warmelt-base+03.cc: Ditto.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@200430 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fortran/trans-intrinsic.c')
-rw-r--r-- | gcc/fortran/trans-intrinsic.c | 243 |
1 files changed, 230 insertions, 13 deletions
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 83e3acf9eea..3fbf193d03c 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -2192,9 +2192,9 @@ gfc_conv_intrinsic_ttynam (gfc_se * se, gfc_expr * expr) minmax (a1, a2, a3, ...) { mvar = a1; - if (a2 .op. mvar || isnan(mvar)) + if (a2 .op. mvar || isnan (mvar)) mvar = a2; - if (a3 .op. mvar || isnan(mvar)) + if (a3 .op. mvar || isnan (mvar)) mvar = a3; ... return mvar @@ -2749,7 +2749,7 @@ gfc_conv_intrinsic_arith (gfc_se * se, gfc_expr * expr, enum tree_code op, if (norm2) { - /* if (x(i) != 0.0) + /* if (x (i) != 0.0) { absX = abs(x(i)) if (absX > scale) @@ -3104,7 +3104,7 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) else { mpz_t asize; - if (gfc_array_size (arrayexpr, &asize) == SUCCESS) + if (gfc_array_size (arrayexpr, &asize)) { nonempty = gfc_conv_mpz_to_tree (asize, gfc_index_integer_kind); mpz_clear (asize); @@ -3594,7 +3594,7 @@ gfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, enum tree_code op) else { mpz_t asize; - if (gfc_array_size (arrayexpr, &asize) == SUCCESS) + if (gfc_array_size (arrayexpr, &asize)) { nonempty = gfc_conv_mpz_to_tree (asize, gfc_index_integer_kind); mpz_clear (asize); @@ -5249,12 +5249,10 @@ static void gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr) { gfc_expr *arg; - gfc_se argse,eight; + gfc_se argse; tree type, result_type, tmp; arg = expr->value.function.actual->expr; - gfc_init_se (&eight, NULL); - gfc_conv_expr (&eight, gfc_get_int_expr (expr->ts.kind, NULL, 8)); gfc_init_se (&argse, NULL); result_type = gfc_get_int_type (expr->ts.kind); @@ -5285,11 +5283,12 @@ gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr) if (arg->ts.type == BT_CHARACTER) tmp = size_of_string_in_bytes (arg->ts.kind, argse.string_length); else - tmp = fold_convert (result_type, size_in_bytes (type)); + tmp = size_in_bytes (type); + tmp = fold_convert (result_type, tmp); done: se->expr = fold_build2_loc (input_location, MULT_EXPR, result_type, tmp, - eight.expr); + build_int_cst (result_type, BITS_PER_UNIT)); gfc_add_block_to_block (&se->pre, &argse.pre); } @@ -5435,9 +5434,8 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr) source = gfc_conv_descriptor_data_get (argse.expr); source_type = gfc_get_element_type (TREE_TYPE (argse.expr)); - /* Repack the source if not a full variable array. */ - if (arg->expr->expr_type == EXPR_VARIABLE - && arg->expr->ref->u.ar.type != AR_FULL) + /* Repack the source if not simply contiguous. */ + if (!gfc_is_simply_contiguous (arg->expr, false)) { tmp = gfc_build_addr_expr (NULL_TREE, argse.expr); @@ -6302,6 +6300,213 @@ gfc_conv_intrinsic_loc (gfc_se * se, gfc_expr * expr) se->expr = temp_var; } + +/* The following routine generates code for the intrinsic + functions from the ISO_C_BINDING module: + * C_LOC + * C_FUNLOC + * C_ASSOCIATED */ + +static void +conv_isocbinding_function (gfc_se *se, gfc_expr *expr) +{ + gfc_actual_arglist *arg = expr->value.function.actual; + + if (expr->value.function.isym->id == GFC_ISYM_C_LOC) + { + if (arg->expr->rank == 0) + gfc_conv_expr_reference (se, arg->expr); + else if (gfc_is_simply_contiguous (arg->expr, false)) + gfc_conv_array_parameter (se, arg->expr, true, NULL, NULL, NULL); + else + { + gfc_conv_expr_descriptor (se, arg->expr); + se->expr = gfc_conv_descriptor_data_get (se->expr); + } + + /* TODO -- the following two lines shouldn't be necessary, but if + they're removed, a bug is exposed later in the code path. + This workaround was thus introduced, but will have to be + removed; please see PR 35150 for details about the issue. */ + se->expr = convert (pvoid_type_node, se->expr); + se->expr = gfc_evaluate_now (se->expr, &se->pre); + } + else if (expr->value.function.isym->id == GFC_ISYM_C_FUNLOC) + gfc_conv_expr_reference (se, arg->expr); + else if (expr->value.function.isym->id == GFC_ISYM_C_ASSOCIATED) + { + gfc_se arg1se; + gfc_se arg2se; + + /* Build the addr_expr for the first argument. The argument is + already an *address* so we don't need to set want_pointer in + the gfc_se. */ + gfc_init_se (&arg1se, NULL); + gfc_conv_expr (&arg1se, arg->expr); + gfc_add_block_to_block (&se->pre, &arg1se.pre); + gfc_add_block_to_block (&se->post, &arg1se.post); + + /* See if we were given two arguments. */ + if (arg->next->expr == NULL) + /* Only given one arg so generate a null and do a + not-equal comparison against the first arg. */ + se->expr = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, + arg1se.expr, + fold_convert (TREE_TYPE (arg1se.expr), + null_pointer_node)); + else + { + tree eq_expr; + tree not_null_expr; + + /* Given two arguments so build the arg2se from second arg. */ + gfc_init_se (&arg2se, NULL); + gfc_conv_expr (&arg2se, arg->next->expr); + gfc_add_block_to_block (&se->pre, &arg2se.pre); + gfc_add_block_to_block (&se->post, &arg2se.post); + + /* Generate test to compare that the two args are equal. */ + eq_expr = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, + arg1se.expr, arg2se.expr); + /* Generate test to ensure that the first arg is not null. */ + not_null_expr = fold_build2_loc (input_location, NE_EXPR, + boolean_type_node, + arg1se.expr, null_pointer_node); + + /* Finally, the generated test must check that both arg1 is not + NULL and that it is equal to the second arg. */ + se->expr = fold_build2_loc (input_location, TRUTH_AND_EXPR, + boolean_type_node, + not_null_expr, eq_expr); + } + } + else + gcc_unreachable (); +} + + +/* The following routine generates code for the intrinsic + subroutines from the ISO_C_BINDING module: + * C_F_POINTER + * C_F_PROCPOINTER. */ + +static tree +conv_isocbinding_subroutine (gfc_code *code) +{ + gfc_se se; + gfc_se cptrse; + gfc_se fptrse; + gfc_se shapese; + gfc_ss *shape_ss; + tree desc, dim, tmp, stride, offset; + stmtblock_t body, block; + gfc_loopinfo loop; + gfc_actual_arglist *arg = code->ext.actual; + + gfc_init_se (&se, NULL); + gfc_init_se (&cptrse, NULL); + gfc_conv_expr (&cptrse, arg->expr); + gfc_add_block_to_block (&se.pre, &cptrse.pre); + gfc_add_block_to_block (&se.post, &cptrse.post); + + gfc_init_se (&fptrse, NULL); + if (arg->next->expr->rank == 0) + { + fptrse.want_pointer = 1; + gfc_conv_expr (&fptrse, arg->next->expr); + gfc_add_block_to_block (&se.pre, &fptrse.pre); + gfc_add_block_to_block (&se.post, &fptrse.post); + if (arg->next->expr->symtree->n.sym->attr.proc_pointer + && arg->next->expr->symtree->n.sym->attr.dummy) + fptrse.expr = build_fold_indirect_ref_loc (input_location, + fptrse.expr); + se.expr = fold_build2_loc (input_location, MODIFY_EXPR, + TREE_TYPE (fptrse.expr), + fptrse.expr, + fold_convert (TREE_TYPE (fptrse.expr), + cptrse.expr)); + gfc_add_expr_to_block (&se.pre, se.expr); + gfc_add_block_to_block (&se.pre, &se.post); + return gfc_finish_block (&se.pre); + } + + gfc_start_block (&block); + + /* Get the descriptor of the Fortran pointer. */ + fptrse.descriptor_only = 1; + gfc_conv_expr_descriptor (&fptrse, arg->next->expr); + gfc_add_block_to_block (&block, &fptrse.pre); + desc = fptrse.expr; + + /* Set data value, dtype, and offset. */ + tmp = GFC_TYPE_ARRAY_DATAPTR_TYPE (TREE_TYPE (desc)); + gfc_conv_descriptor_data_set (&block, desc, fold_convert (tmp, cptrse.expr)); + gfc_add_modify (&block, gfc_conv_descriptor_dtype (desc), + gfc_get_dtype (TREE_TYPE (desc))); + + /* Start scalarization of the bounds, using the shape argument. */ + + shape_ss = gfc_walk_expr (arg->next->next->expr); + gcc_assert (shape_ss != gfc_ss_terminator); + gfc_init_se (&shapese, NULL); + + gfc_init_loopinfo (&loop); + gfc_add_ss_to_loop (&loop, shape_ss); + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop, &arg->next->expr->where); + gfc_mark_ss_chain_used (shape_ss, 1); + + gfc_copy_loopinfo_to_se (&shapese, &loop); + shapese.ss = shape_ss; + + stride = gfc_create_var (gfc_array_index_type, "stride"); + offset = gfc_create_var (gfc_array_index_type, "offset"); + gfc_add_modify (&block, stride, gfc_index_one_node); + gfc_add_modify (&block, offset, gfc_index_zero_node); + + /* Loop body. */ + gfc_start_scalarized_body (&loop, &body); + + dim = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type, + loop.loopvar[0], loop.from[0]); + + /* Set bounds and stride. */ + gfc_conv_descriptor_lbound_set (&body, desc, dim, gfc_index_one_node); + gfc_conv_descriptor_stride_set (&body, desc, dim, stride); + + gfc_conv_expr (&shapese, arg->next->next->expr); + gfc_add_block_to_block (&body, &shapese.pre); + gfc_conv_descriptor_ubound_set (&body, desc, dim, shapese.expr); + gfc_add_block_to_block (&body, &shapese.post); + + /* Calculate offset. */ + gfc_add_modify (&body, offset, + fold_build2_loc (input_location, PLUS_EXPR, + gfc_array_index_type, offset, stride)); + /* Update stride. */ + gfc_add_modify (&body, stride, + fold_build2_loc (input_location, MULT_EXPR, + gfc_array_index_type, stride, + fold_convert (gfc_array_index_type, + shapese.expr))); + /* Finish scalarization loop. */ + gfc_trans_scalarizing_loops (&loop, &body); + gfc_add_block_to_block (&block, &loop.pre); + gfc_add_block_to_block (&block, &loop.post); + gfc_add_block_to_block (&block, &fptrse.post); + gfc_cleanup_loop (&loop); + + gfc_add_modify (&block, offset, + fold_build1_loc (input_location, NEGATE_EXPR, + gfc_array_index_type, offset)); + gfc_conv_descriptor_offset_set (&block, desc, offset); + + gfc_add_expr_to_block (&se.pre, gfc_finish_block (&block)); + gfc_add_block_to_block (&se.pre, &se.post); + return gfc_finish_block (&se.pre); +} + + /* Generate code for an intrinsic function. Some map directly to library calls, others get special handling. In some cases the name of the function used depends on the type specifiers. */ @@ -6477,6 +6682,12 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr) gfc_conv_intrinsic_bitcomp (se, expr, LT_EXPR); break; + case GFC_ISYM_C_ASSOCIATED: + case GFC_ISYM_C_FUNLOC: + case GFC_ISYM_C_LOC: + conv_isocbinding_function (se, expr); + break; + case GFC_ISYM_ACHAR: case GFC_ISYM_CHAR: gfc_conv_intrinsic_char (se, expr); @@ -7586,6 +7797,12 @@ gfc_conv_intrinsic_subroutine (gfc_code *code) res = conv_intrinsic_atomic_ref (code); break; + case GFC_ISYM_C_F_POINTER: + case GFC_ISYM_C_F_PROCPOINTER: + res = conv_isocbinding_subroutine (code); + break; + + default: res = NULL_TREE; break; |