]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cobol: Improved MOVE routines.
authorRobert Dubner <rdubner@symas.com>
Thu, 18 Jun 2026 15:25:57 +0000 (11:25 -0400)
committerRobert Dubner <rdubner@symas.com>
Thu, 18 Jun 2026 16:10:26 +0000 (12:10 -0400)
Faster routine for converting numeric-display numerical strings to
binary values.  Improved conversion of binary values to big-endian
COMP-4 values.

gcc/cobol/ChangeLog:

* cbldiag.h (current_program_index): Suppress cppcheck warning.
(struct cbl_loc_t): Likewise.
* genutil.cc (get_depending_on_value_from_odo): Check subscript
against occurs-depending-on value.
(get_data_offset): Likewise.
(digit): Fast string-to-binary routine.
(num_disp_dive): Likewise.
(get_binary_value_tree): Likewise.
(copy_little_endian_into_place): Move the function to move.cc.
(get_location): Normalize use of "data" pointer versus using the
address of a known variable.
* genutil.h (copy_little_endian_into_place): Remove declarations.
* move.cc (get_reference_to_data): Eliminate function.
(mh_identical): Simplify the logic that uses get_location.
(copy_little_endian_into_place):  Use the routine for both little-
and big-endian targets.  Take absolute value of signed inputs when
the target is unsigned.
(mh_little_endian): Handle both little- and big-endian targets.
* symbols.cc (cbl_alphabet_t::cbl_alphabet_t):  Suppress
cppcheck warning.

gcc/cobol/cbldiag.h
gcc/cobol/genutil.cc
gcc/cobol/genutil.h
gcc/cobol/move.cc
gcc/cobol/symbols.cc

index 827667bdcbd857c15a24958e8fb375630deda4b0..5df71fa68d3e1f2303e8340c3c8b0c28d665066a 100644 (file)
@@ -96,6 +96,7 @@ size_t current_program_index();
  *  These are user-facing messages.  They go through the gcc
  *  diagnostic framework and use text that can be localized.
  */
+// cppcheck-suppress syntaxError
 void yyerror( const char fmt[], ... ) ATTRIBUTE_GCOBOL_DIAG(1, 2);
 
 struct cbl_loc_base_t {
@@ -115,7 +116,7 @@ struct cbl_loc_t : public cbl_loc_base_t {
         last_line, last_column
       }
   {}
-  cbl_loc_t( const cbl_loc_base_t& base ) : cbl_loc_base_t(base)
+  cbl_loc_t( const cbl_loc_base_t& base ) : cbl_loc_base_t(base)   // cppcheck-suppress noExplicitConstructor
   {}
 #if 0
   cbl_loc_t(   int first_line, int first_column,
index f703951f1697dd178064c1c7486e277b4a07c485..74a027bc229e08e174d24f3fd557dcfc5a07767c 100644 (file)
@@ -431,7 +431,7 @@ get_depending_on_value_from_odo(tree retval, cbl_field_t *odo)
 
   if( !enabled_exceptions.match(ec_bound_odo_e) )
     {
-    // With no exception testing, just pick up the value.  If there is a
+    // With no exception testing, just pick up the value.  If there is an error
     // the programmer will simply have to live with the consequences.
     get_integer_value(retval,
                       depending_on,
@@ -729,6 +729,16 @@ get_data_offset(const cbl_refer_t &refer, int *pflags = NULL)
           tree value64 = gg_define_variable(LONG);
           cbl_field_t *odo = symbol_find_odo(parent);
           get_depending_on_value_from_odo(value64, odo);
+
+          IF( subscript, gt_op, value64 )
+            {
+            set_exception_code(ec_bound_odo_e);
+            }
+          ELSE
+            {
+            }
+          ENDIF
+
           }
         }
 
@@ -763,6 +773,131 @@ get_data_offset(const cbl_refer_t &refer, int *pflags = NULL)
   return retval;
   }
 
+static tree
+digit(tree location, int offset, int stride)
+  {
+  return gg_bitwise_and(gg_indirect(location,
+                                    build_int_cst_type(SIZE_T,
+                                                       offset*stride)),
+                        build_int_cst_type(UCHAR, 0x0F));
+  }
+
+static tree
+num_disp_dive(tree location,  // UCHAR_P to first digit
+              int  digits,    //
+              bool signable,
+              int stride)
+  {
+  tree retval;
+  tree type;
+  if( digits <= 9 )
+    {
+    type = signable ? INT : UINT;
+    }
+  else if( digits < 19 )
+    {
+    type = signable ? LONG : ULONG;
+    }
+  else
+    {
+    type = signable ? INT128 : UINT128;
+    }
+  retval = gg_define_variable(type);
+
+  switch(digits)
+    {
+    case 1:
+      {
+      gg_assign(retval, gg_cast(type, digit(location, 0, stride)));
+      break;
+      }
+    case 2:
+      {
+      tree term_a = gg_multiply(gg_cast(type, digit(location, 0, stride)),
+                                build_int_cst_type(type, 10));
+      tree term_b = gg_cast(type, digit(location, 1, stride));
+      gg_assign(retval,
+                gg_add(term_a,
+                       term_b));
+      break;
+      }
+    case 3:
+      {
+      tree term_a = gg_multiply(gg_cast(type, digit(location, 0, stride)),
+                                build_int_cst_type(type, 100));
+      tree term_b = gg_multiply(gg_cast(type, digit(location, 1, stride)),
+                                build_int_cst_type(type, 10));
+      tree term_c = gg_cast(type, digit(location, 2, stride));
+      gg_assign(retval,
+                gg_add(term_a,
+                       gg_add(term_b,
+                              term_c)));
+      break;
+      }
+    case 4:
+      {
+      tree term_a = gg_multiply(gg_cast(type, digit(location, 0, stride)),
+                                build_int_cst_type(type, 1000));
+      tree term_b = gg_multiply(gg_cast(type, digit(location, 1, stride)),
+                                build_int_cst_type(type, 100));
+      tree term_c = gg_multiply(gg_cast(type, digit(location, 2, stride)),
+                                build_int_cst_type(type, 10));
+      tree term_d = gg_cast(type, digit(location, 3, stride));
+      gg_assign(retval,
+                gg_add(term_a,
+                gg_add(term_b,
+                gg_add(term_c,
+                       term_d))));
+      break;
+      }
+    default:
+      {
+      // digits is between 5 and 38
+      int nright = digits/2;
+      int nleft  = digits - nright;
+
+      int64_t right_factor = 0;
+      switch(nright)
+        {
+        // Look!  A ziggurat!
+        case  2: right_factor = 100ULL; break;
+        case  3: right_factor = 1000ULL; break;
+        case  4: right_factor = 10000ULL; break;
+        case  5: right_factor = 100000ULL; break;
+        case  6: right_factor = 1000000ULL; break;
+        case  7: right_factor = 10000000ULL; break;
+        case  8: right_factor = 100000000ULL; break;
+        case  9: right_factor = 1000000000ULL; break;
+        case 10: right_factor = 10000000000ULL; break;
+        case 11: right_factor = 100000000000ULL; break;
+        case 12: right_factor = 1000000000000ULL; break;
+        case 13: right_factor = 10000000000000ULL; break;
+        case 14: right_factor = 100000000000000ULL; break;
+        case 15: right_factor = 1000000000000000ULL; break;
+        case 16: right_factor = 10000000000000000ULL; break;
+        case 17: right_factor = 100000000000000000ULL; break;
+        case 18: right_factor = 1000000000000000000ULL; break;
+        case 19: right_factor = 10000000000000000000ULL; break;
+        }
+      tree term_a = gg_multiply(num_disp_dive(location,
+                                              nleft,
+                                              signable,
+                                              stride),
+                                build_int_cst_type(type, right_factor));
+      tree term_b = num_disp_dive(gg_add(location,
+                                          build_int_cst_type(SIZE_T,
+                                                             nleft*stride)),
+                                  nright,
+                                  signable,
+                                  stride);
+      gg_assign(retval, gg_add(term_a, term_b));
+      break;
+      }
+    }
+
+  return retval;
+  }
+
 tree
 get_binary_value_tree(tree return_type,
                       tree rdigits,
@@ -771,7 +906,7 @@ get_binary_value_tree(tree return_type,
                       tree         hilo
                       )
   {
-  tree retval;
+  tree retval = gg_define_variable(return_type);
 
   if( hilo )
     {
@@ -784,7 +919,7 @@ get_binary_value_tree(tree return_type,
   // Very special case:
   if( strcmp(field->name, "ZEROS") == 0 )
     {
-    retval = gg_cast(return_type, integer_zero_node);
+    gg_assign(retval, gg_cast(return_type, integer_zero_node));
     if( rdigits )
       {
       gg_assign(rdigits, gg_cast(TREE_TYPE(rdigits), integer_zero_node));
@@ -792,7 +927,6 @@ get_binary_value_tree(tree return_type,
     return retval;
     }
 
-  tree pointer = gg_define_variable(UCHAR_P);
   switch(field->type)
     {
     case FldLiteralN:
@@ -808,128 +942,118 @@ get_binary_value_tree(tree return_type,
           gg_assign(rdigits, build_int_cst_type(TREE_TYPE(rdigits),
                                                 field->data.rdigits));
           }
-        retval = gg_cast(return_type, field->data_decl_node);
+        gg_assign(retval, gg_cast(return_type, field->data_decl_node));
         }
       break;
       }
 
     case FldNumericDisplay:
       {
-      const charmap_t *charmap = __gg__get_charmap(field->codeset.encoding);
+      charmap_t *charmap = __gg__get_charmap(field->codeset.encoding);
       int stride = charmap->stride();
-
       // Establish the source
-      tree source_address = get_data_address(field, field_offset);
+      tree source_location = gg_define_variable(UCHAR_P);
+      gg_assign(source_location, get_data_address(field, field_offset));
+      tree sign_location;
+      if(    (field->attr & signable_e)
+          && (field->attr & leading_e)
+          && (field->attr & separate_e) )
+        {
+        sign_location = gg_define_variable(UCHAR_P);
+        gg_assign(sign_location, source_location);
+        gg_assign(source_location,
+                  gg_add(source_location,
+                         build_int_cst_type(SIZE_T, stride)));
+        }
+      // source_location points to the first digit.
+
+      tree dive_value = num_disp_dive(source_location,
+                                      field->data.digits,
+                                      !!(field->attr & signable_e),
+                                      stride);
+      gg_assign(retval, gg_cast(return_type, dive_value));
+
+      // retval is the absolute value of the numeric-display string.
 
-      // We need to check early on for HIGH-VALUE and LOW-VALUE
-      // Pick up the byte
-      tree digit = gg_get_indirect_reference(source_address, NULL_TREE);
-      IF( digit, eq_op, build_int_cst(UCHAR, DEGENERATE_HIGH_VALUE) )
+      if( field->attr & signable_e )
         {
-        // We are dealing with HIGH-VALUE
-        if( hilo )
+        // Because the source is signable, we have to check if it is flagged
+        // as negative:
+        if(   (field->attr & leading_e)
+           && (field->attr & separate_e) )
           {
-          gg_assign(hilo, integer_one_node);
+          // We already know that sign_location is established
           }
-        if( rdigits )
+        else if(   !(field->attr & leading_e)
+                &&  (field->attr & separate_e) )
           {
-          gg_assign(rdigits,
-                    build_int_cst_type( TREE_TYPE(rdigits),
-                                        get_scaled_rdigits(field)));
+          sign_location = gg_define_variable(UCHAR_P);
+          gg_assign(sign_location,
+                    gg_add(source_location,
+                           build_int_cst_type(SIZE_T,
+                                              field->data.digits*stride)));
           }
-        retval = build_int_cst_type(return_type, 0x7FFFFFFFFFFFFFFFUL);
-        }
-      ELSE
-        {
-        IF( digit, eq_op, build_int_cst(UCHAR, DEGENERATE_LOW_VALUE) )
+        else if(    (field->attr & leading_e)
+                && !(field->attr & separate_e) )
           {
-          // We are dealing with LOW-VALUE
-          if( hilo )
-            {
-            gg_assign(hilo, integer_minus_one_node);
-            }
+          sign_location = gg_define_variable(UCHAR_P);
+          gg_assign(sign_location, source_location);
           }
-        ELSE
+        else //if(   !(field->attr & leading_e)
+             //   && !(field->attr & separate_e) )
           {
-          // We are dealing with an ordinary NumericDisplay value
-          gg_assign(pointer, source_address);
-
-          if( rdigits )
+          sign_location = gg_define_variable(UCHAR_P);
+          gg_assign(sign_location,
+                    gg_add(source_location,
+                           build_int_cst_type(SIZE_T,
+                                            (field->data.digits-1)*stride)));
+          }
+        if( field->attr & separate_e )
+          {
+          IF( gg_indirect(sign_location),
+              eq_op,
+              build_int_cst_type(UCHAR,
+                                 charmap->mapped_character(ascii_minus)) )
             {
-            gg_assign(rdigits,
-                      build_int_cst_type(TREE_TYPE(rdigits),
-                                         get_scaled_rdigits(field)));
+            gg_assign(retval, gg_negate(retval));
             }
-          // This will be the 128-bit value of the character sequence
-          tree val128 = gg_define_variable(INT128);
-          // This is a pointer to the sign byte
-          tree signp = gg_define_variable(UCHAR_P);
-          // We need to figure out where the sign information, if any is to be
-          // found:
-          if( field->attr & signable_e )
+          ELSE
             {
-            // The variable is signed
-            if( field->attr & separate_e )
+            }
+          ENDIF
+          }
+        else
+          {
+          if( charmap->is_like_ebcdic() )
+            {
+            IF( gg_indirect(sign_location),
+                lt_op,
+                build_int_cst_type(UCHAR, 0xF0) )
               {
-              // The sign byte is separate
-              if( field->attr & leading_e)
-                {
-                // The first byte is '+' or '-'
-                gg_assign(signp, source_address);
-                // Increment pointer to point to the first actual digit
-                gg_increment(pointer);
-                }
-              else
-                {
-                // The final byte is '+' or '-'
-                gg_assign(signp,
-                          gg_add(source_address,
-                                build_int_cst_type(SIZE_T,
-                                                  field->data.digits*stride)));
-                }
+              // The digit is less than the EBCDIC '0'
+              gg_assign(retval, gg_negate(retval));
               }
-            else
+            ELSE
               {
-              // The sign byte is internal
-              if( field->attr & leading_e)
-                {
-                // The first byte has the sign bit.
-                gg_assign(signp, source_address);
-                }
-              else
-                {
-                // The final byte has the sign bit.
-                gg_assign(signp,
-                          gg_add(source_address,
-                                build_int_cst_type( SIZE_T,
-                                              (field->data.digits-1)*stride)));
-                }
               }
+            ENDIF
             }
           else
             {
-            // This value is unsigned, so just use the first location:
-            gg_assign(signp, source_address);
+            IF( gg_indirect(sign_location),
+                gt_op,
+                build_int_cst_type(UCHAR, 0x39) )
+              {
+              // The digit is greater than the ASCII '9'
+              gg_assign(retval, gg_negate(retval));
+              }
+            ELSE
+              {
+              }
+            ENDIF
             }
-
-          gg_assign(val128,
-                    gg_call_expr( INT128,
-                                  "__gg__numeric_display_to_binary",
-                                  signp,
-                                  pointer,
-                                  build_int_cst_type(INT, field->data.digits),
-                              build_int_cst_type(INT, field->codeset.encoding),
-                              NULL_TREE));
-          // Assign the value we got from the string to our "return" value:
-
-          // Note that cppcheck can't understand the run-time IF()
-          // cppcheck-suppress redundantAssignment
-          retval = gg_cast(return_type, val128);
           }
-        ENDIF
         }
-      ENDIF
-
       break;
       }
 
@@ -1714,54 +1838,6 @@ rt_error(const char *msg)
   gg_abort();
   }
 
-void
-copy_little_endian_into_place(cbl_field_t *dest,
-                              tree         dest_offset,
-                              tree value,
-                              int rhs_rdigits,
-                              bool check_for_error,
-                        const tree &size_error)
-  {
-  if( check_for_error )
-    {
-    // We need to see if value can fit into destref
-
-    // We do this by comparing value to 10^(lhs.ldigits + rhs_rdigits)
-    // Example:  rhs is 123.45, whichis 12345 with rdigits 2
-    // lhs is 99.999.  So, lhs.digits is 5, and lhs.rdigits is 3.
-    // 10^(5 - 3 + 2) is 10^4, which is 10000.  Because 12345 is >= 10000, the
-    // source can't fit into the destination.
-
-    tree abs_value = gg_define_variable(TREE_TYPE(value));
-    gg_assign(abs_value, gg_abs(value));
-
-    FIXED_WIDE_INT(128) power_of_ten = get_power_of_ten(  dest->data.digits
-                                                        - dest->data.rdigits
-                                                        + rhs_rdigits );
-    IF( gg_cast(INT128, abs_value),
-        ge_op,
-        wide_int_to_tree(INT128, power_of_ten) )
-      {
-      // Flag the size error
-      gg_assign(size_error, integer_one_node);
-      }
-    ELSE
-      ENDIF
-    }
-  scale_by_power_of_ten_N(value, dest->data.rdigits - rhs_rdigits);
-
-  // Create a variable of our target type.
-  tree dest_type = tree_type_from_field(dest);
-  tree target = gg_define_variable(dest_type);
-  // Cast the source to the target
-  gg_assign(target, gg_cast(dest_type, value));
-  tree dest_pointer = gg_add(member(dest->var_decl_node, "data"),
-                             dest_offset);
-  // Copy the target to the destination.
-  gg_memcpy(dest_pointer,
-            gg_get_address_of(target),
-            build_int_cst_type(SIZE_T, gg_sizeof(dest_type)));
-  }
 
 tree
 build_array_of_referlets( size_t N,
@@ -3075,34 +3151,21 @@ get_location(tree &retval, const cbl_refer_t &refer)
 
   if( refer_is_super_clean(refer) )
     {
-    // Working storage, not external, no refmods or subscripts:
-    // gg_assign(retval, member(refer.field->var_decl_node,"data"));
-
-#if 0
-    /* This should work.  It doesn't.  This needs investigating.  */
-    // To prevent aliasing problems, we use a memcpy
-    gg_memcpy(gg_get_address_of(retval),
-             gg_get_address(refer.field->data_decl_node),
-              build_int_cst_type(SIZE_T, gg_sizeof(UCHAR_P)));
+    // Working storage, not external, no refmods or subscripts.  That means
+    // we can work with the actual data item, and save a level of indirection.
 
     if( refer.field->offset )
       {
-      tree offset = build_int_cst_type(SIZE_T, refer.field->offset);
-      gg_assign(retval, gg_add(retval, offset));
-      }
-#else
-    tree base   = gg_cast(UCHAR_P,
-                          gg_get_address(refer.field->data_decl_node));
-    if( refer.field->offset )
-      {
-      tree offset = build_int_cst_type(SIZE_T, refer.field->offset);
-      gg_assign(retval, gg_cast(UCHAR_P, gg_add(base, offset)));
+      gg_assign(retval,
+                gg_add(gg_cast(UCHAR_P,
+                               gg_get_address(refer.field->data_decl_node)),
+                build_int_cst_type(SIZE_T, refer.field->offset)));
       }
     else
       {
-      gg_assign(retval, base);
+      gg_assign(retval, gg_cast(UCHAR_P,
+                            gg_get_address(refer.field->data_decl_node)));
       }
-#endif
     }
   else
     {
index 56fca1c0824133952551dd6e462bed22bc467401..dbcc10bec30b84985a0d7a75eb47884cd88f7cb3 100644 (file)
@@ -106,12 +106,6 @@ void      get_integer_value(tree value,  // This is always a LONG
                             tree         offset=NULL,  // size_t
                             bool check_for_fractional_digits=false);
 void      rt_error(const char *msg);
-void      copy_little_endian_into_place(cbl_field_t *dest,
-                                        tree         dest_offset,
-                                        tree value,
-                                        int rhs_rdigits,
-                                        bool check_for_error,
-                                  const tree &size_error);
 tree      build_array_of_size_t( size_t  N,
                                  const size_t *values);
 void      parser_display_internal_field(tree file_descriptor,
index 536d471e66ba0b94b1b374cd746b56fcd00a0b23..531b8b69a58e678101ef4936917481e56c952e44 100644 (file)
@@ -92,131 +92,6 @@ is_figconst(const cbl_refer_t &sourceref)
   return is_figconst_t(sourceref.field);
   }
 
-static tree
-get_reference_to_data(cbl_field_t *field)
-  {
-  // Given a field, we can derive the type of data the field needs to provide.
-  // That field has a field->data_decl_node, which is the starting point for
-  // the reference to the data we calculate.
-  tree retval = NULL_TREE;
-  tree field_type = data_decl_type_for(field);
-  tree data_type  = TREE_TYPE(field->data_decl_node);
-  bool field_is_array = TREE_CODE(field_type) == ARRAY_TYPE;
-  bool data_is_array  = TREE_CODE(data_type) == ARRAY_TYPE;
-
-  int field_code = TREE_CODE(field_type);
-  int data_code  = TREE_CODE(data_type);
-  size_t field_size = TREE_INT_CST_LOW(TYPE_SIZE_UNIT(field_type));
-  size_t data_size  = TREE_INT_CST_LOW(TYPE_SIZE_UNIT(data_type));
-
-  if( field_code == data_code && field_size == data_size )
-    {
-    if( !field_is_array )
-      {
-      // The two types are the same and are not ARRAY_TYPE
-      if( field->offset == 0 )
-        {
-        // This is an "ah, that feels good" moment.  Getting here means the
-        // field is something like "77 foo pic 9999" and that means the
-        // data_decl_node is exactly what is needed.
-        retval = field->data_decl_node;
-        }
-      else
-        {
-        // We have an offset.
-        if( (field->offset % field_size) == 0 )
-          {
-          // The offset is an integer number of bytes from data_decl_node:
-          size_t index = field->offset % field_size;
-          retval = gg_indirect( gg_cast(build_pointer_type(data_type),
-                                     gg_get_address_of(field->data_decl_node)),
-                               build_int_cst_type(SIZE_T, index));
-          }
-        else
-          {
-          // The offset is some random number of bytes.  We need to do a
-          // retval = *(data_type *)((char *)&data_decl_node + offset)
-          tree base = gg_get_address_of(field->data_decl_node);
-          base = gg_cast(UCHAR_P, base);
-          base = gg_add(base, build_int_cst_type(SIZE_T, field->offset));
-          retval = gg_cast(field_type, gg_indirect(base));
-          }
-        }
-      }
-    else
-      {
-      // The two types are the same ARRAY_TYPE
-      retval = gg_cast(UCHAR_P, gg_pointer_to_array(field->data_decl_node));
-      if( field->offset )
-        {
-        retval = gg_add(retval, build_int_cst_type(SIZE_T, field->offset));
-        }
-      }
-    }
-  else if( field_is_array && data_is_array )
-    {
-    // We have two different array types
-    retval = gg_cast(UCHAR_P, gg_pointer_to_array(field->data_decl_node));
-    if( field->offset )
-      {
-      retval = gg_add(retval, build_int_cst_type(SIZE_T, field->offset));
-      }
-    }
-  else if( !field_is_array && !data_is_array )
-    {
-    // The two data types are different, and neither is an array
-    if( field->offset == 0 )
-      {
-      if( field_size == data_size )
-        {
-        // The offset is zero, and the sizes are the same.
-        // This must be something like REDEFINES or the like:
-        retval = gg_cast(field_type, field->data_decl_node);
-        }
-      else
-        {
-        // The sizes are different:
-        // retval = *(data_type *)((char *)&data_decl_node)
-        tree base = gg_get_address_of(field->data_decl_node);
-        retval = gg_indirect(gg_cast(build_pointer_type(field_type), base));
-        }
-      }
-    else
-      {
-      // There is an offset
-      tree base = gg_get_address_of(field->data_decl_node);
-      base = gg_cast(UCHAR_P, base);
-      base = gg_add(base, build_int_cst_type(SIZE_T, field->offset));
-      retval = gg_indirect(gg_cast(build_pointer_type(field_type), base));
-      }
-    }
-  else if( !field_is_array && data_is_array )
-    {
-    // The return is a scalar, but we start from an array.
-    tree base = gg_pointer_to_array(field->data_decl_node);
-    base = gg_cast(UCHAR_P, base);
-    if( field->offset )
-      {
-      base = gg_add(base, build_int_cst_type(SIZE_T, field->offset));
-      }
-    base = gg_cast(build_pointer_type(field_type), base);
-    retval = gg_indirect(base);
-    }
-  else // if( field_is_array !data_is_array )
-    {
-    // The return is an array, but we start from a scalar
-    tree base = gg_get_address_of(field->data_decl_node);
-    base = gg_cast(UCHAR_P, base);
-    if( field->offset )
-      {
-      base = gg_add(base, build_int_cst_type(SIZE_T, field->offset));
-      }
-    retval = base;
-    }
-
-  return retval;
-  }
-
 static void
 conditional_abs(tree source, const cbl_field_t *field)
   {
@@ -313,24 +188,15 @@ mh_identical(const cbl_refer_t &destref,
       {
       // They are identical, and they have no subscripts
 
-      tree source = get_reference_to_data(sourceref.field);
-      tree dest   = get_reference_to_data(destref.field);
+      tree source;
+      tree dest;
+      get_location(source, sourceref);
+      get_location(dest, destref);
 
-      tree type = data_decl_type_for(destref.field);
-      if( TREE_CODE(type) == ARRAY_TYPE )
-        {
-        // We are dealing with pointers to UCHAR.
-        // The move has to be done with a copy:
-        gg_memcpy(dest,
-                  source,
-                  build_int_cst_type(SIZE_T,
-                                     destref.field->data.capacity()));
-        }
-      else
-        {
-        // We are dealing with scalars
-        gg_assign(dest, source);
-        }
+      gg_memcpy(dest,
+                source,
+                build_int_cst_type(SIZE_T,
+                                   destref.field->data.capacity()));
       moved = true;
       }
     }
@@ -1402,6 +1268,67 @@ mh_numeric_display( const cbl_refer_t &destref,
   return moved;
   }
 
+static void
+copy_little_endian_into_place(cbl_field_t *dest,
+                              tree         dest_offset,
+                              tree value,
+                              int rhs_rdigits,
+                              bool check_for_error,
+                        const tree &size_error)
+  {
+  if( !(dest->attr & signable_e) )
+    {
+    gg_assign(value, gg_abs(value));
+    }
+
+  if( check_for_error )
+    {
+    // We need to see if value can fit into destref
+
+    // We do this by comparing value to 10^(lhs.ldigits + rhs_rdigits)
+    // Example:  rhs is 123.45, whichis 12345 with rdigits 2
+    // lhs is 99.999.  So, lhs.digits is 5, and lhs.rdigits is 3.
+    // 10^(5 - 3 + 2) is 10^4, which is 10000.  Because 12345 is >= 10000, the
+    // source can't fit into the destination.
+
+    tree abs_value = gg_define_variable(TREE_TYPE(value));
+    gg_assign(abs_value, gg_abs(value));
+
+    FIXED_WIDE_INT(128) power_of_ten = get_power_of_ten(  dest->data.digits
+                                                        - dest->data.rdigits
+                                                        + rhs_rdigits );
+    IF( gg_cast(INT128, abs_value),
+        ge_op,
+        wide_int_to_tree(INT128, power_of_ten) )
+      {
+      // Flag the size error
+      gg_assign(size_error, integer_one_node);
+      }
+    ELSE
+      ENDIF
+    }
+  scale_by_power_of_ten_N(value, dest->data.rdigits - rhs_rdigits);
+
+  // Create a variable of our target type.
+  tree dest_type = tree_type_from_field(dest);
+  tree target = gg_define_variable(dest_type);
+  // Cast the source to the target
+  gg_assign(target, gg_cast(dest_type, value));
+
+  tree dest_pointer = gg_define_variable(UCHAR_P);
+  gg_assign(dest_pointer, gg_add(member(dest->var_decl_node, "data"),
+                                 dest_offset));
+
+  if( dest->type == FldNumericBinary )
+    {
+    gg_assign(target, gg_bswap(target));
+    }
+  // Copy the target to the destination.
+  gg_memcpy(dest_pointer,
+            gg_get_address_of(target),
+            build_int_cst_type(SIZE_T, gg_sizeof(dest_type)));
+  }
+
 static bool
 mh_little_endian( const cbl_refer_t &destref,
                   const cbl_refer_t &sourceref,
@@ -1409,6 +1336,9 @@ mh_little_endian( const cbl_refer_t &destref,
                         bool check_for_error,
                         tree size_error)
   {
+  // The name of this routine is misleading.  It also handles big-endian
+  // destinations.
+
   bool moved = false;
 
   cbl_figconst_t figconst = cbl_figconst_of( sourceref.field->data.original());
@@ -1422,6 +1352,7 @@ mh_little_endian( const cbl_refer_t &destref,
       &&  sourceref.field->type     != FldNumericEdited
       &&  sourceref.field->type     != FldPacked
       &&  (     destref.field->type == FldNumericBin5
+            ||  destref.field->type == FldNumericBinary
             ||  destref.field->type == FldPointer
             ||  destref.field->type == FldIndex ) )
     {
index 2cf73cc4cf499d6ca9be4614bc66d6258c8dd1d9..2513892b0b20eaaa16933856500ed2d12a9f09eb 100644 (file)
@@ -3411,7 +3411,9 @@ cbl_locale_t::cbl_locale_t( const cbl_name_t name, const char iconv_name[] ) {
   }
 }
 
-cbl_alphabet_t::cbl_alphabet_t(const cbl_loc_t& loc, size_t locale, cbl_name_t name )
+cbl_alphabet_t::cbl_alphabet_t(const cbl_loc_t& loc,
+                               size_t locale,
+                               cbl_name_t name ) // cppcheck-suppress constParameter
   : loc(loc)
   , locale(locale)
   , low_index(0)