From: Robert Dubner <[email protected]>
Date: Mon, 1 Jun 2026 22:50:28 -0400
Subject: [PATCH] cobol: Improve execution speed of FUNCTION TRIM.

By breaking out specific code for FUNCTION TRIM when the string is
single-byte-coded ASCII or EBCDIC, and by creating a matching
__gg__trim_1 routine using std::find_if(), the function operates about
fifteen to 25 times faster than it did.

gcc/cobol/ChangeLog:

        * compare.cc (cobol_compare_relop): Rename the cobol_compare_relop
        function.
        (cobol_compare): Likewise.
        * compare.h (cobol_compare_relop): Likewise.
        (cobol_compare): Likewise.
        * genapi.cc (parser_display): Refine the use of SYSPUNCH_e for
        inserting debugging comments into the assembly language.
        (parser_relop): Use "cobol_compare".
        (handle_gg_trim): Break out SBC TRIM logic.
        (parser_intrinsic_call_2): Likewise.
        (parser_bsearch_when): Use "cobol_compare"
        * genutil.cc (refer_is_super_clean): FldLiteralN is always "super
        clean".
        (is_pure_integer): Make binary_from_FldNumericBin5 "static bool".
        (binary_from_FldLiteralN): New function.
        (get_binary_value): Use the new function.

libgcobol/ChangeLog:

        * intrinsic.cc (__gg__trim): Eliminate useless comment.
        (__gg__trim_1): New function.
---
 gcc/cobol/compare.cc   |  8 ++--
 gcc/cobol/compare.h    |  8 ++--
 gcc/cobol/genapi.cc    | 84 ++++++++++++++++++++++++++++++++++--------
 gcc/cobol/genutil.cc   | 45 +++++++++++++++++-----
 libgcobol/intrinsic.cc | 55 ++++++++++++++++++++++++++-
 5 files changed, 167 insertions(+), 33 deletions(-)

diff --git a/gcc/cobol/compare.cc b/gcc/cobol/compare.cc
index a3d6ff37c4c..3fade5813d3 100644
--- a/gcc/cobol/compare.cc
+++ b/gcc/cobol/compare.cc
@@ -1368,10 +1368,10 @@ compare_class( tree        &left,
   }
 
 void
-cobol_compare_relop(tree        &left,
-                    tree        &right,
-              const cbl_refer_t &left_side,
-              const cbl_refer_t &right_side)
+cobol_compare(tree        &left,
+              tree        &right,
+        const cbl_refer_t &left_side,
+        const cbl_refer_t &right_side)
   {
   // This routine figures out how to compare left_side to right_side, and
   // returns the trees 'left' and 'right' in numeric form that can be
turned
diff --git a/gcc/cobol/compare.h b/gcc/cobol/compare.h
index d20ac94c32d..d966c58f7b3 100644
--- a/gcc/cobol/compare.h
+++ b/gcc/cobol/compare.h
@@ -34,9 +34,9 @@
     "left" and "right" var_decl trees, which can be fed directly into one
of
     the six relational expressions like EQ_EXPR, LT_EXPR, and so on. */
 
-void cobol_compare_relop( tree        &left,
-                          tree        &right,
-                    const cbl_refer_t &left_side,
-                    const cbl_refer_t &right_side);
+void cobol_compare( tree        &left,
+                    tree        &right,
+              const cbl_refer_t &left_side,
+              const cbl_refer_t &right_side);
 
 #endif
diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 7bda84d85a4..ecc37031a00 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -5254,7 +5254,6 @@ parser_display( const struct cbl_special_name_t
*upon,
       case SYSOUT_e:
       case SYSLIST_e:
       case SYSLST_e:
-      case SYSPUNCH_e:
       case SYSPCH_e:
         // In the 21st century, when there are no longer valid
assumptions to
         // be made about the existence of line printers, and where things
@@ -5269,6 +5268,22 @@ parser_display( const struct cbl_special_name_t
*upon,
         needs_closing = true;
         break;
 
+      case SYSPUNCH_e:
+        // With the ASSEMBLER environment variable, SYSPUNCH means
"insert
+        // the text into the assembly language".  So, we don't need a
file
+        // descriptor.
+        if( !getenv("ASSEMBLER") )
+          {
+          gg_assign(file_descriptor,
+                    gg_call_expr( INT,
+                                  "__gg__get_file_descriptor",
+                                  gg_string_literal(upon->os_filename),
+                                  NULL_TREE));
+          needs_closing = true;
+          }
+        break;
+
+
       case ARG_NUM_e:
         // Set the index number for a subsequent ACCEPT FROM ARG_VALUE_e
         gg_call(VOID,
@@ -7736,7 +7751,7 @@ parser_relop(   cbl_field_t *tgt,
 
   tree left;
   tree right;
-  cobol_compare_relop(left, right, aref, bref);
+  cobol_compare(left, right, aref, bref);
   tgt->var_decl_node = gg_build_relational_expression(left,
                                                       relop,
                                                       right);
@@ -11377,6 +11392,38 @@ parser_intrinsic_call_1( cbl_field_t *tgt,
     }
   }
 
+static bool
+handle_gg_trim(cbl_field_t *tgt,
+               const char function_name[],
+         const cbl_refer_t& ref1,
+         const cbl_refer_t& ref2 )
+  {
+  bool handled = false;
+  if( strcmp(function_name, "__gg__trim") == 0 )
+    {
+    charmap_t *charmap = __gg__get_charmap(ref1.field->codeset.encoding);
+    if(charmap->stride() == 1)
+      {
+      uint8_t space = charmap->mapped_character(ascii_space);
+      int how = atoi(ref2.field->data.original());
+      if( how == 0 )
+        {
+        how = 3;
+        }
+      gg_call(VOID,
+              "__gg__trim_1",
+              gg_get_address_of(tgt->var_decl_node),
+              gg_get_address_of(ref1.field->var_decl_node),
+              refer_offset(ref1),
+              refer_size_source(ref1),
+              build_int_cst_type(INT, (space<<8) + how),
+              NULL_TREE);
+      handled = true;
+      }
+    }
+  return handled;
+  }
+
 void
 parser_intrinsic_call_2( cbl_field_t *tgt,
                        const char function_name[],
@@ -11404,17 +11451,24 @@ parser_intrinsic_call_2( cbl_field_t *tgt,
     }
   store_location_stuff(function_name);
 
-  gg_call(VOID,
-          function_name,
-          gg_get_address_of(tgt->var_decl_node),
-          gg_get_address_of(ref1.field->var_decl_node),
-          refer_offset(ref1),
-          refer_size_source(ref1),
-          ref2.field ? gg_get_address_of(ref2.field->var_decl_node)
-                     : null_pointer_node,
-          refer_offset(ref2),
-          refer_size_source(ref2),
-          NULL_TREE);
+  if( handle_gg_trim(tgt, function_name, ref1, ref2) )
+    {
+    // The specialty routine did the job
+    }
+  else
+    {
+    gg_call(VOID,
+            function_name,
+            gg_get_address_of(tgt->var_decl_node),
+            gg_get_address_of(ref1.field->var_decl_node),
+            refer_offset(ref1),
+            refer_size_source(ref1),
+            ref2.field ? gg_get_address_of(ref2.field->var_decl_node)
+                       : null_pointer_node,
+            refer_offset(ref2),
+            refer_size_source(ref2),
+            NULL_TREE);
+    }
   TRACE1
     {
     TRACE1_INDENT
@@ -12010,11 +12064,11 @@ parser_bsearch_when(cbl_label_t* name,
   tree right;
   if( ascending )
     {
-    cobol_compare_relop(left, right, key, sarg);
+    cobol_compare(left, right, key, sarg);
     }
   else
     {
-    cobol_compare_relop(left, right, sarg, key);
+    cobol_compare(left, right, sarg, key);
     }
 
   IF( left, lt_op, right )
diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc
index c93673815f1..283864c85cc 100644
--- a/gcc/cobol/genutil.cc
+++ b/gcc/cobol/genutil.cc
@@ -2024,13 +2024,19 @@ refer_is_super_clean(const cbl_refer_t &refer)
   // otherwise in condition so that we can use refer.field->var_data_node
for
   // GENERIC, thus getting rid the additional level of indirection
through
   // the refer.field->var_decl_node::data pointer
-  return   refer_is_clean(refer)
-        && !(refer.field->attr & (  based_e
-                                  | linkage_e
-                                  | local_e
-                                  | intermediate_e
-                                  | any_length_e
-                                  | external_e)) ;
+
+  // Note: By rights, FldLiteralA should be super-clean, but errors ensue
when
+  // it is made so.  This should be tracked down.  The disconnect might
be in
+  // get_location().
+  return     // refer.field->type == FldLiteralA ||
+             refer.field->type == FldLiteralN
+           || (refer_is_clean(refer)
+              && !(refer.field->attr & (  based_e
+                                        | linkage_e
+                                        | local_e
+                                        | intermediate_e
+                                        | any_length_e
+                                        | external_e))) ;
   }
 
 bool
@@ -2316,7 +2322,7 @@ is_pure_integer(const cbl_field_t *field)
   return retval;
   }
 
-bool
+static bool
 binary_from_FldNumericBin5(tree &value, const cbl_refer_t &refer, tree
type)
   {
   bool retval = false;
@@ -2403,6 +2409,24 @@ binary_from_FldNumericBin5(tree &value, const
cbl_refer_t &refer, tree type)
   return retval;
   }
 
+static bool
+binary_from_FldLiteralN(tree &value, const cbl_refer_t &refer, tree type)
+  {
+  // The data_decl_node has the value we need.
+
+  tree source_type = tree_type_from_field(refer.field);
+  if( !type )
+    {
+    type = source_type;
+    }
+
+  value = gg_define_variable(type);
+  gg_assign(value, gg_cast(type, refer.field->data_decl_node));
+
+  return true;
+  }
+
+
 bool
 binary_from_FldNumericBinary(tree &value, const cbl_refer_t &refer, tree
type)
   {
@@ -3116,8 +3140,11 @@ get_binary_value(tree &value, const cbl_refer_t
&refer, tree type)
     // We know that the refer is a type that involves an integer binary
value.
     switch(refer.field->type)
       {
-      case FldNumericBin5:
       case FldLiteralN:
+        retval = binary_from_FldLiteralN(value, refer, type);
+        break;
+
+      case FldNumericBin5:
       case FldIndex:
       case FldPointer:
         retval = binary_from_FldNumericBin5(value, refer, type);
diff --git a/libgcobol/intrinsic.cc b/libgcobol/intrinsic.cc
index c81429fc36e..dce815acc85 100644
--- a/libgcobol/intrinsic.cc
+++ b/libgcobol/intrinsic.cc
@@ -3530,7 +3530,6 @@ __gg__trim( cblc_field_t *dest,
                                                           arg2,
                                                           arg2_offset,
                                                           arg2_size);
-  //static const int BOTH     = 0;
   #define LEADING  1  // Remove leading  spaces
   #define TRAILING 2  // Remove trailing spaces
 
@@ -5840,3 +5839,57 @@ __gg__locale_time_from_seconds( cblc_field_t *dest,
   __gg__field_from_string(dest, 0, dest->capacity, converted,
bytes_converted);
   free(converted);
   }
+
+
+extern "C"
+void
+__gg__trim_1( cblc_field_t *dest,
+        const cblc_field_t *src,
+              size_t        src_offset,
+              size_t        src_size,
+              int           space_how ) // (space<<8) + how
+  {
+  // This is the no-holds-barred, do-it-as-fast-as-possible, TRIM
routine. It
+  // gets called only when the stride is 1.  Spaces is eight bytes of the
+  // character to be trimmed away, usually 0x2020202020202020 because we
are
+  // usually working in ASCII.  'how' indicates LEADING and TRAILING.
+
+  #define LEADING  1  // Remove leading  spaces
+  #define TRAILING 2  // Remove trailing spaces
+
+  const uint8_t *left  = src->data + src_offset;    // Leftmost
character
+  const uint8_t *right = left      + src_size;      // One past the end
+
+  uint8_t space = space_how >> 8;
+
+  if ((space_how & LEADING) && left < right)
+    {
+    left = std::find_if(left, right, [space](uint8_t c)
+      {
+          return c != space;
+      });
+    }
+
+  if( (space_how & TRAILING) && left < right)
+    {
+    right = std::find_if(
+        std::make_reverse_iterator(right),
+        std::make_reverse_iterator(left),
+        [space](uint8_t c) { return c != space; }
+    ).base();
+    }
+
+  size_t bytes_converted = right - left;
+  __gg__adjust_dest_size(dest, bytes_converted);
+
+#if 0
+  __gg__field_from_string(dest, 0, dest->capacity, reinterpret_cast<const
char *>(left), bytes_converted);
+#else
+  memcpy(dest->data,
+         left,
+         bytes_converted);
+#endif
+
+  return;
+  }
+
-- 
2.34.1

Reply via email to