This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gfortran] String intrinsics


The attached patch implements the TRIM and REPEAT intrinsic functions. It 
also fixes the LEN intrinsic.

Applied to tree-ssa branch.

Paul

2003-10-11  Huang Chun  <jiwang@mail.edu.cn>

	* check.c (gfc_check_repeat): Check arguments are scalar.
	(gfc_check_trim): New function.
	* intrinsic.h (gfc_check_trim): Add prototype.
	* intrinsic.c (add_functions): Use it.
	* trans.h (gfor_fndecl_string_trim, gfor_fndecl_string_repeat):
	Decalare.
	* trans-decl.c: Ditto.
	(gfc_build_intrinsic_fucntion_decls): Set them.
	* trans-intrinsic.c (gfc_conv_intrinsic_len): Handle result vars.
	(gfc_conv_intrinsic_trim): New function.
	(gfc_conv_intrinsic_repeat): New function.
	(gfc_conv_intrinsic_function): Use them.
libgfortran
	* intrinsics/string_intrinsics.c (string_trim): New function.
	(string_repeat): New function.
testsuite
	* gfortran.fortran-torture/execute/intrinsic_len.f90: New test.
	* gfortran.fortran-torture/execute/intrinsic_trim.f90: New test.
diff -uprxCVS clean/tree-ssa/gcc/fortran/check.c gcc/gcc/fortran/check.c
--- clean/tree-ssa/gcc/fortran/check.c	2003-09-14 18:08:25.000000000 +0100
+++ gcc/gcc/fortran/check.c	2003-10-11 22:42:44.000000000 +0100
@@ -1352,9 +1352,15 @@ gfc_check_repeat (gfc_expr * x, gfc_expr
   if (type_check (x, 0, BT_CHARACTER) == FAILURE)
     return FAILURE;
 
+  if (scalar_check (x, 0) == FAILURE)
+    return FAILURE;
+
   if (type_check (y, 0, BT_INTEGER) == FAILURE)
     return FAILURE;
 
+  if (scalar_check (y, 1) == FAILURE)
+    return FAILURE;
+
   return SUCCESS;
 }
 
@@ -1667,6 +1673,19 @@ gfc_check_verify (gfc_expr * x, gfc_expr
 }
 
 
+try
+gfc_check_trim (gfc_expr * x)
+{
+  if (type_check (x, 0, BT_CHARACTER) == FAILURE)
+    return FAILURE;
+
+  if (scalar_check (x, 0) == FAILURE)
+    return FAILURE;
+
+   return SUCCESS;
+}
+
+
 /* Common check function for the half a dozen intrinsics that have a
    single real argument.  */
 
diff -uprxCVS clean/tree-ssa/gcc/fortran/intrinsic.c gcc/gcc/fortran/intrinsic.c
--- clean/tree-ssa/gcc/fortran/intrinsic.c	2003-10-11 20:18:36.000000000 +0100
+++ gcc/gcc/fortran/intrinsic.c	2003-10-11 22:36:49.000000000 +0100
@@ -1552,7 +1552,7 @@ add_functions (void)
   make_generic ("transpose", GFC_ISYM_TRANSPOSE);
 
   add_sym_1 ("trim", 0, 1, BT_CHARACTER, dc,
-	     NULL, gfc_simplify_trim, gfc_resolve_trim,
+	     gfc_check_trim, gfc_simplify_trim, gfc_resolve_trim,
 	     stg, BT_CHARACTER, dc, 0);
 
   make_generic ("trim", GFC_ISYM_TRIM);
diff -uprxCVS clean/tree-ssa/gcc/fortran/intrinsic.h gcc/gcc/fortran/intrinsic.h
--- clean/tree-ssa/gcc/fortran/intrinsic.h	2003-10-11 20:18:36.000000000 +0100
+++ gcc/gcc/fortran/intrinsic.h	2003-10-11 23:11:58.000000000 +0100
@@ -90,6 +90,7 @@ try gfc_check_spread (gfc_expr *, gfc_ex
 try gfc_check_sum (gfc_expr *, gfc_expr *, gfc_expr *);
 try gfc_check_transfer (gfc_expr *, gfc_expr *, gfc_expr *);
 try gfc_check_transpose (gfc_expr *);
+try gfc_check_trim (gfc_expr *);
 try gfc_check_ubound (gfc_expr *, gfc_expr *);
 try gfc_check_unpack (gfc_expr *, gfc_expr *, gfc_expr *);
 try gfc_check_verify (gfc_expr *, gfc_expr *, gfc_expr *);
diff -uprxCVS clean/tree-ssa/gcc/fortran/trans-decl.c gcc/gcc/fortran/trans-decl.c
--- clean/tree-ssa/gcc/fortran/trans-decl.c	2003-10-11 20:18:36.000000000 +0100
+++ gcc/gcc/fortran/trans-decl.c	2003-10-11 22:36:49.000000000 +0100
@@ -116,6 +116,8 @@ tree gfor_fndecl_string_len_trim;
 tree gfor_fndecl_string_index;
 tree gfor_fndecl_string_scan;
 tree gfor_fndecl_string_verify;
+tree gfor_fndecl_string_trim;
+tree gfor_fndecl_string_repeat;
 tree gfor_fndecl_adjustl;
 tree gfor_fndecl_adjustr;
 
@@ -1286,6 +1288,24 @@ gfc_build_intrinsic_function_decls (void
                                      gfc_strlen_type_node, pchar_type_node,
                                      gfc_logical4_type_node);
 
+  gfor_fndecl_string_trim = 
+    gfc_build_library_function_decl (get_identifier (PREFIX("string_trim")),
+                                     void_type_node,
+                                     4,
+                                     build_pointer_type (gfc_strlen_type_node),
+                                     ppvoid_type_node,
+                                     gfc_strlen_type_node,
+                                     pchar_type_node);
+
+  gfor_fndecl_string_repeat =
+    gfc_build_library_function_decl (get_identifier (PREFIX("string_repeat")),
+                                     void_type_node,
+                                     4,
+                                     pchar_type_node,
+                                     gfc_strlen_type_node,
+                                     pchar_type_node,
+                                     gfc_int4_type_node);
+
   gfor_fndecl_adjustl =
     gfc_build_library_function_decl (get_identifier (PREFIX("adjustl")),
 				     void_type_node,
diff -uprxCVS clean/tree-ssa/gcc/fortran/trans-intrinsic.c gcc/gcc/fortran/trans-intrinsic.c
--- clean/tree-ssa/gcc/fortran/trans-intrinsic.c	2003-10-11 21:59:38.000000000 +0100
+++ gcc/gcc/fortran/trans-intrinsic.c	2003-10-11 22:43:33.000000000 +0100
@@ -1773,6 +1773,7 @@ gfc_conv_intrinsic_len (gfc_se * se, gfc
   tree len;
   tree type;
   tree decl;
+  gfc_symbol *sym;
   gfc_se argse;
   gfc_expr *arg;
 
@@ -1784,7 +1785,14 @@ gfc_conv_intrinsic_len (gfc_se * se, gfc
   switch (arg->expr_type)
     {
     case EXPR_VARIABLE:
-      decl = gfc_get_symbol_decl (arg->symtree->n.sym);
+      sym = arg->symtree->n.sym;
+      decl = gfc_get_symbol_decl (sym);
+      if (decl == current_function_decl && sym->attr.function
+            && (sym->result == sym))
+        {
+          decl = gfc_get_fake_result_decl (sym);
+        }
+
       assert (GFC_DECL_STRING (decl));
       len = GFC_DECL_STRING_LENGTH (decl);
       assert (len);
@@ -2965,6 +2973,79 @@ gfc_conv_intrinsic_sr_kind (gfc_se * se,
 }
 
 
+/* Generate code for TRIM (A) intrinsic function.  */
+
+static void
+gfc_conv_intrinsic_trim (gfc_se * se, gfc_expr * expr)
+{
+  tree var;
+  tree len;
+  tree addr;
+  tree tmp;
+  tree arglist;
+  tree type;
+  tree cond;
+
+  arglist = NULL_TREE;
+
+  type = build_pointer_type (gfc_character1_type_node);
+  var = gfc_create_var (type, "pstr");
+  addr = build1 (ADDR_EXPR, ppvoid_type_node, var);
+  len = gfc_create_var (gfc_int4_type_node, "len");
+
+  tmp = gfc_conv_intrinsic_function_args (se, expr);
+  arglist = gfc_chainon_list (arglist, build1 (ADDR_EXPR, 
+	build_pointer_type(TREE_TYPE(len)), len));
+  arglist = gfc_chainon_list (arglist, addr);
+  arglist = chainon (arglist, tmp);
+  
+  tmp = gfc_build_function_call (gfor_fndecl_string_trim, arglist);
+  gfc_add_expr_to_block (&se->pre, tmp);
+
+  /* Free the temporary afterwards, if necessary.  */
+  cond = build (GT_EXPR, boolean_type_node, len, integer_zero_node);
+  arglist = gfc_chainon_list (NULL_TREE, addr);
+  tmp = gfc_build_function_call (gfor_fndecl_internal_free, arglist);
+  tmp = build_v (COND_EXPR, cond, tmp, build_empty_stmt ());
+  gfc_add_expr_to_block (&se->post, tmp);
+
+  se->expr = var;
+  se->string_length = len;
+}
+
+
+/* Generate code for REPEAT (STRING, NCOPIES) intrinsic function.  */
+
+static void
+gfc_conv_intrinsic_repeat (gfc_se * se, gfc_expr * expr)
+{
+  tree tmp;
+  tree len;
+  tree args;
+  tree arglist;
+  tree ncopies;
+  tree var;
+  tree type;
+
+  args = gfc_conv_intrinsic_function_args (se, expr);
+  len = TREE_VALUE (args);
+  tmp = gfc_advance_chain (args, 2);
+  ncopies = TREE_VALUE (tmp);
+  len = fold (build (MULT_EXPR, gfc_int4_type_node, len, ncopies));
+  type = gfc_get_character_type (expr->ts.kind, expr->ts.cl);
+  var = gfc_conv_string_tmp (se, build_pointer_type (type), len);
+
+  arglist = NULL_TREE;
+  arglist = gfc_chainon_list (arglist, var);
+  arglist = chainon (arglist, args);
+  tmp = gfc_build_function_call (gfor_fndecl_string_repeat, arglist);
+  gfc_add_expr_to_block (&se->pre, tmp);
+
+  se->expr = var;
+  se->string_length = len;
+}
+
+
 /* 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.  */
@@ -2998,9 +3079,15 @@ gfc_conv_intrinsic_function (gfc_se * se
       abort ();
 
     case GFC_ISYM_CSHIFT:
+      gfc_todo_error ("Intrinsic %s", expr->value.function.name);
+
     case GFC_ISYM_REPEAT:
+      gfc_conv_intrinsic_repeat (se, expr);
+      break;
+
     case GFC_ISYM_TRIM:
-      gfc_todo_error ("Intrinsic %s", expr->value.function.name);
+      gfc_conv_intrinsic_trim (se, expr);
+      break;
 
     case GFC_ISYM_SI_KIND:
       gfc_conv_intrinsic_si_kind (se, expr);
diff -uprxCVS clean/tree-ssa/gcc/fortran/trans.h gcc/gcc/fortran/trans.h
--- clean/tree-ssa/gcc/fortran/trans.h	2003-09-21 15:30:23.000000000 +0100
+++ gcc/gcc/fortran/trans.h	2003-10-11 22:36:49.000000000 +0100
@@ -447,6 +447,8 @@ extern GTY(()) tree gfor_fndecl_string_l
 extern GTY(()) tree gfor_fndecl_string_index;
 extern GTY(()) tree gfor_fndecl_string_scan;
 extern GTY(()) tree gfor_fndecl_string_verify;
+extern GTY(()) tree gfor_fndecl_string_trim;
+extern GTY(()) tree gfor_fndecl_string_repeat;
 extern GTY(()) tree gfor_fndecl_adjustl;
 extern GTY(()) tree gfor_fndecl_adjustr;
 
diff -uprxCVS clean/tree-ssa/libgfortran/intrinsics/string_intrinsics.c gcc/libgfortran/intrinsics/string_intrinsics.c
--- clean/tree-ssa/libgfortran/intrinsics/string_intrinsics.c	2003-09-19 20:04:42.000000000 +0100
+++ gcc/libgfortran/intrinsics/string_intrinsics.c	2003-10-11 23:55:09.000000000 +0100
@@ -64,6 +64,11 @@ GFC_INTEGER_4 string_scan (GFC_INTEGER_4
 GFC_INTEGER_4 string_verify (GFC_INTEGER_4, const char *, GFC_INTEGER_4,
                              const char *, GFC_LOGICAL_4);
 
+#define string_trim prefix(string_trim)
+void string_trim (GFC_INTEGER_4 *, void **, GFC_INTEGER_4, const char *);
+
+#define string_repeat prefix(string_repeat)
+void string_repeat (char *, GFC_INTEGER_4, const char *, GFC_INTEGER_4);
 
 /* The two areas may overlap so we use memmove.  */
 
@@ -160,6 +165,32 @@ concat_string (GFC_INTEGER_4 destlen, ch
 }
 
 
+/* Return string with all trailing blanks removed.  */
+
+void
+string_trim (GFC_INTEGER_4 * len, void ** dest, GFC_INTEGER_4 slen, const char * src)
+{
+  int i;
+
+  /* Determine length of result string.  */
+  for (i = slen - 1; i >= 0; i--)
+    {
+      if (src[i] != ' ')
+        break;
+    }
+  *len = i + 1;
+
+  if (*len > 0)
+    {
+      /* Allocate space for result string.  */
+      internal_malloc (dest, *len);
+
+      /* copy string if necessary.  */
+      memmove (*dest, src, *len);
+    }
+}
+
+
 /* The length of a string not including trailing blanks.  */
 
 GFC_INTEGER_4
@@ -337,3 +368,27 @@ string_verify (GFC_INTEGER_4 slen, const
 
   return 0;
 }
+
+
+/* Concatenate several copies of a string.  */
+
+void
+string_repeat (char * dest, GFC_INTEGER_4 slen, 
+               const char * src, GFC_INTEGER_4 ncopies)
+{
+  int i;
+
+  /* See if ncopies is valid.  */
+  if (ncopies < 0)
+    {
+      /* The error is already reported.  */
+      runtime_error ("Augument NCOPIES is negative.");
+    }
+
+  /* Copy characters.  */
+  for (i = 0; i < ncopies; i++) 
+    {
+      memmove (dest + (i * slen), src, slen);
+    }
+}
+

Attachment: intrinsic_trim.f90
Description: Text document

Attachment: intrinsic_len.f90
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]