aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
authorFeng Wang <fengwang@nudt.edu.cn>2006-01-09 02:27:45 +0000
committerFeng Wang <fengwang@gcc.gnu.org>2006-01-09 02:27:45 +0000
commit0a821a922eadddf1c9a1e8f558ac669df3f2e374 (patch)
tree06ce878d70c9a53f32fa40b3f08dc1bcb7dc3b5a /gcc/fortran
parent7d60270a87ee95b8b67b3f86442a648600ba36cb (diff)
downloadgcc-0a821a922eadddf1c9a1e8f558ac669df3f2e374.zip
gcc-0a821a922eadddf1c9a1e8f558ac669df3f2e374.tar.gz
gcc-0a821a922eadddf1c9a1e8f558ac669df3f2e374.tar.bz2
fortran ChangeLog entry:
2006-01-09 Feng Wang <fengwang@nudt.edu.cn> PR fortran/12456 * trans-expr.c (gfc_to_single_character): New function that converts string to single character if its length is 1. (gfc_build_compare_string):New function that compare string and handle single character specially. (gfc_conv_expr_op): Use gfc_build_compare_string. (gfc_trans_string_copy): Use gfc_to_single_character. * trans-intrinsic.c (gfc_conv_intrinsic_strcmp): Use gfc_build_compare_string. * trans.h (gfc_build_compare_string): Add prototype. testsuite ChangeLog entry: 2006-01-09 Feng Wang <fengwang@nudt.edu.cn> PR fortran/12456 * gfortran.dg/single_char_string.f90: New test. From-SVN: r109489
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/ChangeLog13
-rw-r--r--gcc/fortran/trans-expr.c83
-rw-r--r--gcc/fortran/trans-intrinsic.c10
-rw-r--r--gcc/fortran/trans.h3
4 files changed, 94 insertions, 15 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 45fb5fe..a745970 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,5 +1,18 @@
2006-01-09 Feng Wang <fengwang@nudt.edu.cn>
+ PR fortran/12456
+ * trans-expr.c (gfc_to_single_character): New function that converts
+ string to single character if its length is 1.
+ (gfc_build_compare_string):New function that compare string and handle
+ single character specially.
+ (gfc_conv_expr_op): Use gfc_build_compare_string.
+ (gfc_trans_string_copy): Use gfc_to_single_character.
+ * trans-intrinsic.c (gfc_conv_intrinsic_strcmp): Use
+ gfc_build_compare_string.
+ * trans.h (gfc_build_compare_string): Add prototype.
+
+2006-01-09 Feng Wang <fengwang@nudt.edu.cn>
+
* simplify.c (gfc_simplify_char): Use UCHAR_MAX instead of literal
constant.
(gfc_simplify_ichar): Get the result from unsinged char and in the
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index f21c073..e46075e 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -901,7 +901,6 @@ gfc_conv_concat_op (gfc_se * se, gfc_expr * expr)
se->string_length = len;
}
-
/* Translates an op expression. Common (binary) cases are handled by this
function, others are passed on. Recursion is used in either case.
We use the fact that (op1.ts == op2.ts) (except for the power
@@ -1043,23 +1042,15 @@ gfc_conv_expr_op (gfc_se * se, gfc_expr * expr)
gfc_conv_expr (&rse, expr->value.op.op2);
gfc_add_block_to_block (&se->pre, &rse.pre);
- /* For string comparisons we generate a library call, and compare the return
- value with 0. */
if (checkstring)
{
gfc_conv_string_parameter (&lse);
gfc_conv_string_parameter (&rse);
- tmp = NULL_TREE;
- tmp = gfc_chainon_list (tmp, lse.string_length);
- tmp = gfc_chainon_list (tmp, lse.expr);
- tmp = gfc_chainon_list (tmp, rse.string_length);
- tmp = gfc_chainon_list (tmp, rse.expr);
-
- /* Build a call for the comparison. */
- lse.expr = build_function_call_expr (gfor_fndecl_compare_string, tmp);
- gfc_add_block_to_block (&lse.post, &rse.post);
+ lse.expr = gfc_build_compare_string (lse.string_length, lse.expr,
+ rse.string_length, rse.expr);
rse.expr = integer_zero_node;
+ gfc_add_block_to_block (&lse.post, &rse.post);
}
type = gfc_typenode_for_spec (&expr->ts);
@@ -1078,6 +1069,63 @@ gfc_conv_expr_op (gfc_se * se, gfc_expr * expr)
gfc_add_block_to_block (&se->post, &lse.post);
}
+/* If a string's length is one, we convert it to a single character. */
+
+static tree
+gfc_to_single_character (tree len, tree str)
+{
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (str)));
+
+ if (INTEGER_CST_P (len) && TREE_INT_CST_LOW (len) == 1
+ && TREE_INT_CST_HIGH (len) == 0)
+ {
+ str = fold_convert (pchar_type_node, str);
+ return build_fold_indirect_ref (str);
+ }
+
+ return NULL_TREE;
+}
+
+/* Compare two strings. If they are all single characters, the result is the
+ subtraction of them. Otherwise, we build a library call. */
+
+tree
+gfc_build_compare_string (tree len1, tree str1, tree len2, tree str2)
+{
+ tree sc1;
+ tree sc2;
+ tree type;
+ tree tmp;
+
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (str1)));
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (str2)));
+
+ type = gfc_get_int_type (gfc_default_integer_kind);
+
+ sc1 = gfc_to_single_character (len1, str1);
+ sc2 = gfc_to_single_character (len2, str2);
+
+ /* Deal with single character specially. */
+ if (sc1 != NULL_TREE && sc2 != NULL_TREE)
+ {
+ sc1 = fold_convert (type, sc1);
+ sc2 = fold_convert (type, sc2);
+ tmp = fold_build2 (MINUS_EXPR, type, sc1, sc2);
+ }
+ else
+ {
+ tmp = NULL_TREE;
+ tmp = gfc_chainon_list (tmp, len1);
+ tmp = gfc_chainon_list (tmp, str1);
+ tmp = gfc_chainon_list (tmp, len2);
+ tmp = gfc_chainon_list (tmp, str2);
+
+ /* Build a call for the comparison. */
+ tmp = build_function_call_expr (gfor_fndecl_compare_string, tmp);
+ }
+
+ return tmp;
+}
static void
gfc_conv_function_val (gfc_se * se, gfc_symbol * sym)
@@ -1818,6 +1866,17 @@ gfc_trans_string_copy (stmtblock_t * block, tree dlen, tree dest,
tree slen, tree src)
{
tree tmp;
+ tree dsc;
+ tree ssc;
+
+ /* Deal with single character specially. */
+ dsc = gfc_to_single_character (dlen, dest);
+ ssc = gfc_to_single_character (slen, src);
+ if (dsc != NULL_TREE && ssc != NULL_TREE)
+ {
+ gfc_add_modify_expr (block, dsc, ssc);
+ return;
+ }
tmp = NULL_TREE;
tmp = gfc_chainon_list (tmp, dlen);
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index 699a294..4c6d63a 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -2267,13 +2267,17 @@ gfc_conv_intrinsic_strcmp (gfc_se * se, gfc_expr * expr, int op)
{
tree type;
tree args;
+ tree arg2;
args = gfc_conv_intrinsic_function_args (se, expr);
- /* Build a call for the comparison. */
- se->expr = build_function_call_expr (gfor_fndecl_compare_string, args);
+ arg2 = TREE_CHAIN (TREE_CHAIN (args));
+
+ se->expr = gfc_build_compare_string (TREE_VALUE (args),
+ TREE_VALUE (TREE_CHAIN (args)), TREE_VALUE (arg2),
+ TREE_VALUE (TREE_CHAIN (arg2)));
type = gfc_typenode_for_spec (&expr->ts);
- se->expr = build2 (op, type, se->expr,
+ se->expr = fold_build2 (op, type, se->expr,
build_int_cst (TREE_TYPE (se->expr), 0));
}
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 2d637bd..e0b5138 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -268,6 +268,9 @@ void gfc_make_safe_expr (gfc_se * se);
/* Makes sure se is suitable for passing as a function string parameter. */
void gfc_conv_string_parameter (gfc_se * se);
+/* Compare two strings. */
+tree gfc_build_compare_string (tree, tree, tree, tree);
+
/* Add an item to the end of TREE_LIST. */
tree gfc_chainon_list (tree, tree);