>From 3a7ab39c1429dc59eb024583d98dfb9a7b35d2a9 Mon Sep 17 00:00:00 2001
From: Robert Dubner <[email protected]>
Date: Tue, 16 Jun 2026 14:26:24 -0400
Subject: [PATCH] cobol: Simplify tree type determination; eliminate
 file-static variables.

Use tree_type_from_field() and tree_type_from_refer() to replace a number
of similar routines.  Replace a number of specific file-static
variable definitions with non-specific variable definitions.

Repair calculation of DIVIDE ... GIVING REMAINDER where parameters are
negative.

gcc/cobol/ChangeLog:

        * compare.cc (numeric_alpha_compare): Use tree_type_from_refer().
        * genapi.cc (file_static_variable): Eliminate function.
        (psa_FldLiteralN): Use tree_type_from_field.
        (parser_accept_command_line): Eliminate file-static variables.
        (parser_accept_envar): Likewise.
        (parser_assign): Likewise.
        (parser_initialize_table): Likewise.
        (parser_see_stop_run): Likewise.
        (parser_file_write): Likewise.
        (parser_file_start): Likewise.
        (inspect_tally): Likewise.
        (inspect_replacing): Likewise.
        (field_increment): Likewise.
        (parser_match_exception): Likewise.
        * genapi.h (file_static_variable): Eliminate function.
        * genmath.cc (largest_binary_term): Use tree_type_from_refer().
        (fast_add):  Likewise.
        (fast_subtract): Likewise.
        (fast_multiply): Likewise.
        (fast_divide): Likewise.
        (parser_divide): Likewise.
        * genutil.cc (tree_type_from_digits): Eliminate function.
        (get_integer_value): Eliminate file-static variables.
        (get_data_offset): Eliminate file-static variables.
        (get_binary_value_tree): Eliminate file-static variables.
        (tree_type_from_field): Updated function.
        (tree_type_from_refer): New function.
        (scale_by_power_of_ten): Eliminate file-static variables.
        (tree_type_from_size): Eliminate function.
        (copy_little_endian_into_place): Improve logic.
        (build_array_of_size_t): Eliminate file-static variables.
        (refer_refmod_length): Likewise.
        (refer_fill_depends): Likewise.
        (refer_size): Likewise.
        (refer_size_source): Likewise.
        * genutil.h (tree_type_from_digits): Eliminate function.
        (tree_type_from_size): Eliminate function.
        (tree_type_from_refer): New function.
        * lang.opt: Updated documentation.
        * lang.opt.urls: Updated documentation.
        * move.cc (digits_to_bytes): Eliminate function.
        (get_bytes_needed): Likewise.
        (mh_source_is_literalN): Eliminate file-static variables; use
        tree_type_from_refer().
        (mh_numeric_display): Likewise.
        (mh_little_endian): tree_type_from_refer().
        (mh_numdisp_to_packed): Use get_location() function.
        (mh_packed_to_packed): Likewise.
        (mh_packed_to_numdisp): Likewise.
        (move_helper): Likewise.

libgcobol/ChangeLog:

        * gmath.cc (multiply_int256_by_int64): Comment.
        (int256_as_decimal): Handle negative values.
        (__gg__dividef45): Repair remainder logic when numeric-display
        parameters are negative.

gcc/testsuite/ChangeLog:

        * cobol.dg/group2/DIVIDE_binary-long_giving_remainder.cob: New
test.
        * cobol.dg/group2/DIVIDE_binary-long_giving_remainder.out: New
test.
        * cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.cob: New
test.
        * cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.out: New
test.
        *
cobol.dg/group2/GCC_125616_RT3601_-_IBM_incorrect_DISPLAY_of_COMP-1_COMP-2
_float.cob:
        New test.
        *
cobol.dg/group2/PR39_RT3573_-_Parser_issue_w_concat._source_lines.cob: New
test.
---
 gcc/cobol/compare.cc                          |  24 +-
 gcc/cobol/genapi.cc                           |  56 ++---
 gcc/cobol/genapi.h                            |   2 -
 gcc/cobol/genmath.cc                          |  27 +-
 gcc/cobol/genutil.cc                          | 213 ++++------------
 gcc/cobol/genutil.h                           |   3 +-
 gcc/cobol/lang.opt                            |   4 +
 gcc/cobol/lang.opt.urls                       |   3 +
 gcc/cobol/move.cc                             | 236 +++++-------------
 .../DIVIDE_binary-long_giving_remainder.cob   |  26 ++
 .../DIVIDE_binary-long_giving_remainder.out   |   5 +
 ...IVIDE_numeric-display_giving_remainder.cob |  26 ++
 ...IVIDE_numeric-display_giving_remainder.out |   5 +
 ...correct_DISPLAY_of_COMP-1_COMP-2_float.cob |  20 ++
 ..._-_Parser_issue_w_concat._source_lines.cob |  10 +
 libgcobol/gmath.cc                            |  28 ++-
 16 files changed, 267 insertions(+), 421 deletions(-)
 create mode 100644
gcc/testsuite/cobol.dg/group2/DIVIDE_binary-long_giving_remainder.cob
 create mode 100644
gcc/testsuite/cobol.dg/group2/DIVIDE_binary-long_giving_remainder.out
 create mode 100644
gcc/testsuite/cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.cob
 create mode 100644
gcc/testsuite/cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.out
 create mode 100644
gcc/testsuite/cobol.dg/group2/GCC_125616_RT3601_-_IBM_incorrect_DISPLAY_of
_COMP-1_COMP-2_float.cob
 create mode 100644
gcc/testsuite/cobol.dg/group2/PR39_RT3573_-_Parser_issue_w_concat._source_
lines.cob

diff --git a/gcc/cobol/compare.cc b/gcc/cobol/compare.cc
index 3fade5813d3..d04aad45d52 100644
--- a/gcc/cobol/compare.cc
+++ b/gcc/cobol/compare.cc
@@ -1101,26 +1101,8 @@ numeric_alpha_compare(tree        &left,
 
     // The type of the variable should be straightforward.  It is not.
There
     // are various considerations in determining the type.
-    tree type;
-    size_t digits = left_side.field->data.digits;
     tree value;
-    if( digits == 0 )
-      {
-      // This is a pure binary type.
-      type = tree_type_from_size(left_side.field->data.capacity(),
-                                 left_side.field->attr & signable_e);
-      }
-    else
-      {
-      // There is some specified number of digits in the variable:
-      // But if the variable is scaled, we have to multiply by 10^N,
where
-      // N is the number of zeroed P digits:
-      if( left_side.field->data.rdigits < 0 )
-        {
-        digits += -left_side.field->data.rdigits;
-        }
-      type = tree_type_from_digits(digits,
left_side.field->attr&signable_e);
-      }
+    tree type = tree_type_from_refer(left_side);
 
     // We have what we need to get the value:
     get_binary_value(value, left_side, type);
@@ -1197,7 +1179,7 @@ numeric_alpha_compare(tree        &left,
                 "__gg__compare_numeric_all",
                 gg_get_address_of(left),
                 gg_cast(UINT128, value),
-                build_int_cst_type(SIZE_T, digits),
+                build_int_cst_type(SIZE_T, left_side.field->data.digits),
                 build_string_literal(nbytes, converted),
                 build_int_cst_type(SIZE_T, nbytes),
                 build_int_cst_type(INT,
left_side.field->codeset.encoding),
@@ -1214,7 +1196,7 @@ numeric_alpha_compare(tree        &left,
                 "__gg__compare_binary_to_string",
                 gg_get_address_of(left),
                 gg_cast(UINT128, value),
-                build_int_cst_type(SIZE_T, digits),
+                build_int_cst_type(SIZE_T, left_side.field->data.digits),
                 location_right,
                 length_right,
                 build_int_cst_type(INT,
right_side.field->codeset.encoding),
diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index a02d7df4692..c70c8b4ad86 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -115,14 +115,6 @@ line_tick()
 #define line_tick()
 #endif
 
-tree
-file_static_variable(tree type, const char *v)
-  {
-  // This routine returns a reference to an already-defined file_static
-  // variable. You need to know the type that was used for the
definition.
-  return gg_declare_variable(type, v, NULL, vs_file_static);
-  }
-
 // set using -f-trace-debug, defined in lang.opt
 int f_trace_debug;
 
@@ -3720,8 +3712,7 @@ psa_FldLiteralN(struct cbl_field_t *field )
 
   // The value is 1, 2, 4, 8 or 16 bytes, so an ordinary constructor can
be
   // used.
-  var_type = tree_type_from_size( field->data.capacity(),
-                                  field->attr & signable_e);
+  var_type = tree_type_from_field(field);
   tree new_var_decl = gg_define_variable( var_type,
                                           base_name,
                                           vs_static);
@@ -3997,7 +3988,7 @@ parser_accept_command_line( const cbl_refer_t &tgt,
     SHOW_PARSE_END
     }
 
-  static tree erf = gg_define_variable(INT, "..pac_erf", vs_file_static);
+  tree erf = gg_define_variable(INT);
 
   if( !source.field )
     {
@@ -4168,7 +4159,7 @@ parser_accept_envar(const struct cbl_refer_t &tgt,
     TRACE1_END
     }
 
-  static tree erf = gg_define_variable(INT, "..pae_erf", vs_file_static);
+  tree erf = gg_define_variable(INT);
 
   gg_assign(erf,
             gg_call_expr( INT,
@@ -5227,10 +5218,7 @@ parser_assign( size_t nC, cbl_num_result_t *C,
     CHECK_FIELD(destref.field);
     CHECK_FIELD(sourceref.field);
 
-    // gg_printf("parser_assign: The compute_error_code is %d\n",
-    //            gg_cast(INT,
compute_error->structs.compute_error->compute_error_code), NULL_TREE);
-
-    static tree erf = gg_define_variable(INT, "..pa_erf",
vs_file_static);
+    tree erf = gg_define_variable(INT);
     if( on_error )
       {
       // There is an ON ERROR clause.  When there is an ON ERROR clause,
and
@@ -5477,12 +5465,9 @@ parser_initialize_table(size_t nelem,
     }
   typedef size_t span_t[2];
   static_assert(sizeof(spans[0]) == sizeof(span_t), "pair size wrong");
-  static tree tspans = gg_define_variable(SIZE_T_P,
-                                          "..pit_v1",
-                                          vs_file_static);
-  static tree ttbls  = gg_define_variable(SIZE_T_P,
-                                          "..pit_v2",
-vs_file_static);
+  tree tspans = gg_define_variable(SIZE_T_P);
+  tree ttbls  = gg_define_variable(SIZE_T_P);
+
   gg_assign(tspans,
             build_array_of_size_t(2*nspan,
                                   reinterpret_cast<const size_t
*>(spans)));
@@ -7341,7 +7326,7 @@ parser_see_stop_run(struct cbl_refer_t exit_status,
     }
 
   // It's a stop run.  Return return-code to the operating system:
-  static tree returned_value = gg_define_variable(INT, "..pssr_retval",
vs_file_static);
+  tree returned_value = gg_define_variable(INT);
 
   if( exit_status.field )
     {
@@ -9441,10 +9426,10 @@ parser_file_write( cbl_file_t *file,
                         file->name);
     }
 
-  static tree t_advance = gg_define_variable(INT, "..pfw_advance",
vs_file_static);
+  tree t_advance = gg_define_variable(INT);
   if(advance.field)
     {
-    static tree value = gg_define_variable(INT, "..pfw_value",
vs_file_static);
+    tree value = gg_define_variable(INT);
     get_binary_value( value,
                       NULL,
                       advance.field,
@@ -9811,7 +9796,7 @@ parser_file_start(struct cbl_file_t *file,
     flk = -1;
     }
 
-  static tree length = gg_define_variable(SIZE_T, "..pfs_length",
vs_file_static);
+  tree length = gg_define_variable(SIZE_T);
   gg_assign(length, size_t_zero_node);
 
   if( flk > 0 && !length_ref.field )
@@ -9958,8 +9943,8 @@ inspect_tally(bool backward,
   // all the integers and cbl_inspect_bound_t values, in a strict
sequence so
   // that the library routine can peel them off.
 
-  static tree int_size = gg_define_variable(INT,      "..pit_size",
vs_file_static, 0);
-  static tree integers = gg_define_variable(SIZE_T_P, "..pit",
vs_file_static, null_pointer_node);
+  tree int_size = gg_define_variable(INT, integer_zero_node);
+  tree integers = gg_define_variable(SIZE_T_P, null_pointer_node);
 
   size_t n_integers = int_index;
 
@@ -10131,10 +10116,10 @@ inspect_replacing(int backward,
 
   size_t n_integers =   1                     // Room for
operations[0].nbound()
                         + operations[0].nbound()  // Room for all the
cbl_inspect_bound_t values
-                        + n_all_leading_first;  // Room for all of the
n_identifier_3 counts
+                        + n_all_leading_first;  // Room for all of the
n_identifier_3  counts
 
-  static tree int_size = gg_define_variable(INT,      "..pir_size",
vs_file_static, 0);
-  static tree integers = gg_define_variable(SIZE_T_P, "..pir",
vs_file_static, null_pointer_node);
+  tree int_size = gg_define_variable(INT, integer_zero_node);
+  tree integers = gg_define_variable(SIZE_T_P, null_pointer_node);
 
   IF( build_int_cst_type(INT, n_integers), gt_op, int_size )
     {
@@ -11081,10 +11066,11 @@ parser_intrinsic_call_4( cbl_field_t *tgt,
   }
 
 static void
-field_increment(cbl_field_t *fld)
+field_increment(cbl_field_t *fld )
   {
-  static tree value   = gg_define_variable(INT128, "..fi_value",
vs_file_static);
-  static tree rdigits = gg_define_variable(INT,    "..fi_rdigits",
vs_file_static);
+  static tree value   = gg_define_variable(INT128);
+  static tree rdigits = gg_define_variable(INT);
+
   get_binary_value(value, rdigits, fld, size_t_zero_node);
   gg_assign(  value,
               gg_add(value, gg_cast(SIZE_T, integer_one_node)));
@@ -13956,7 +13942,7 @@ parser_match_exception(cbl_field_t *index)
 
   TRACE1
     {
-    static tree index_val = gg_define_variable(INT, "..pme_index",
vs_file_static);
+    tree index_val = gg_define_variable(INT);
     get_binary_value(index_val, NULL, index, size_t_zero_node);
     TRACE1_INDENT
     gg_printf("returned value is 0x%x (%d)", index_val, index_val,
NULL_TREE);
diff --git a/gcc/cobol/genapi.h b/gcc/cobol/genapi.h
index 5dee20f95c6..00c234521fe 100644
--- a/gcc/cobol/genapi.h
+++ b/gcc/cobol/genapi.h
@@ -617,8 +617,6 @@ void parser_init_list_size(int count_of_variables);
 void parser_init_list_element(cbl_field_t *field);
 void parser_init_list();
 
-tree file_static_variable(tree type, const char *name);
-
 void parser_statement_begin( const cbl_name_t name, tree ecs, tree dcls
);
 void parser_statement_end( const std::list<cbl_field_t*>& );
 
diff --git a/gcc/cobol/genmath.cc b/gcc/cobol/genmath.cc
index 3b1c3b74e0b..bdbfe8e691b 100644
--- a/gcc/cobol/genmath.cc
+++ b/gcc/cobol/genmath.cc
@@ -357,12 +357,9 @@ all_refers_integer(size_t nC, const cbl_refer_t *C)
   }
 
 static tree
-largest_binary_term(size_t nA, cbl_refer_t *A)
+largest_binary_term(size_t nA, const cbl_refer_t *A)
   {
   tree retval = NULL_TREE;
-  uint32_t max_capacity = 0;
-  int      is_negative  = 0;
-
   for(size_t i=0; i<nA; i++)
     {
     if( !is_pure_integer(A[i].field) || A[i].field->type == FldFloat )
@@ -381,9 +378,7 @@ largest_binary_term(size_t nA, cbl_refer_t *A)
         )
       {
       // This is an integer type that can be worked with quickly
-      is_negative |= ( A[i].field->attr & signable_e );
-      max_capacity = std::max(max_capacity, A[i].field->data.capacity());
-      retval = tree_type_from_size(max_capacity, is_negative);
+      retval = tree_type_from_refer(A[i]);
       }
     else
       {
@@ -418,8 +413,7 @@ fast_add( size_t nC, cbl_num_result_t *C,
     tree term_type = largest_binary_term(nA, A);
     if( term_type )
       {
-      tree dest_type =
tree_type_from_size(C[0].refer.field->data.capacity(),
-                                           0);
+      tree dest_type = tree_type_from_refer(C[0].refer);
       // All the numbers are integers without rdigits
       if(    nC == 1
           && nA == 1
@@ -637,9 +631,7 @@ fast_subtract(size_t nC, cbl_num_result_t *C,
           )
         {
         // This is the simplest case of all.  Just subtract A from C.
-        tree dest_type = tree_type_from_size(
-
C[0].refer.field->data.capacity(),
-                                          0);
+        tree dest_type = tree_type_from_refer(C[0].refer);
         tree A_value;
         if( refer_is_clean(A[0]) )
           {
@@ -743,7 +735,7 @@ fast_subtract(size_t nC, cbl_num_result_t *C,
         // We now either accumulate into C[n] or assign to C[n]:
         for(size_t i=0; i<nC; i++ )
           {
-          tree dest_type =
tree_type_from_size(C[i].refer.field->data.capacity(), 0);
+          tree dest_type = tree_type_from_refer(C[i].refer);
           tree dest_addr = gg_add(member(C[i].refer.field->var_decl_node,
"data"),
                                   refer_offset(C[i].refer));
           tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
@@ -816,7 +808,7 @@ fast_multiply(size_t nC, cbl_num_result_t *C,
       // We now either multiply into C[n] or assign A * B to C[n]:
       for(size_t i=0; i<nC; i++ )
         {
-        tree dest_type =
tree_type_from_size(C[i].refer.field->data.capacity(), 0);
+        tree dest_type = tree_type_from_refer(C[i].refer);
         tree dest_addr = gg_add(member(C[i].refer.field->var_decl_node,
"data"),
                                 refer_offset(C[i].refer));
         tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
@@ -895,8 +887,7 @@ fast_divide(size_t nC, cbl_num_result_t *C,
       // We now either divide into C[n] or assign dividend/divisor to
C[n]:
       for(size_t i=0; i<nC; i++ )
         {
-        tree dest_type =
-
tree_type_from_size(C[i].refer.field->data.capacity(), 0);
+        tree dest_type = tree_type_from_refer(C[i].refer);
         tree dest_addr = gg_add(member( C[i].refer.field->var_decl_node,
                                         "data"),
                                 refer_offset(C[i].refer));
@@ -923,7 +914,7 @@ fast_divide(size_t nC, cbl_num_result_t *C,
           {
           dest_addr = gg_add( member(remainder.field->var_decl_node,
"data"),
                               refer_offset(remainder));
-          dest_type =
tree_type_from_size(remainder.field->data.capacity(), 0);
+          dest_type = tree_type_from_refer(remainder);
           ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
 
           gg_assign(gg_indirect(ptr),
@@ -2329,7 +2320,7 @@ parser_divide(  size_t nC, cbl_num_result_t *C,  //
C = A / B
                                           nB, B,
                                           remainder) )
     {
-
+    // We were able to do a fast divide operation.
     }
   else
     {
diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc
index e75d1be63eb..f703951f169 100644
--- a/gcc/cobol/genutil.cc
+++ b/gcc/cobol/genutil.cc
@@ -175,60 +175,6 @@ get_scaled_digits(cbl_field_t *field)
   return retval;
   }
 
-tree
-tree_type_from_digits(size_t digits, uint64_t signable)
-  {
-  tree retval = NULL_TREE;
-
-  if( signable )
-    {
-    if(digits <= 2 )
-      {
-      retval = CHAR;
-      }
-    else if (digits <= 4 )
-      {
-      retval = SHORT;
-      }
-    else if (digits <= 9 )
-      {
-      retval = INT;
-      }
-    else if (digits <= 18 )
-      {
-      retval = LONGLONG;
-      }
-    else
-      {
-      retval = INT128;
-      }
-    }
-  else
-    {
-    if(digits <= 2 )
-      {
-      retval = UCHAR;
-      }
-    else if (digits <= 4 )
-      {
-      retval = USHORT;
-      }
-    else if (digits <= 9 )
-      {
-      retval = UINT;
-      }
-    else if (digits <= 18 )
-      {
-      retval = ULONGLONG;
-      }
-    else
-      {
-      retval = UINT128;
-      }
-    }
-  return retval;
-  }
-
 void
 get_integer_value(tree value, // We know this is a LONG
                   cbl_field_t *field,
@@ -249,8 +195,8 @@ get_integer_value(tree value, // We know this is a
LONG
   // If the field_i has rdigits, and if any of those rdigits are
non-zero, we
   // return a 1 so that our caller can decide what to do.
 
-  static tree temp    = gg_define_variable(INT128, "..giv_temp",
vs_file_static);
-  static tree rdigits = gg_define_variable(INT,    "..giv_rdigits",
vs_file_static);
+  tree temp    = gg_define_variable(INT128);
+  tree rdigits = gg_define_variable(INT);
 
   if( field->attr & intermediate_e )
     {
@@ -780,9 +726,7 @@ get_data_offset(const cbl_refer_t &refer, int *pflags
= NULL)
         {
         if( parent->occurs.depending_on )
           {
-          static tree value64 = gg_define_variable( LONG,
-                                                    ".._gdos_value64",
-                                                    vs_file_static);
+          tree value64 = gg_define_variable(LONG);
           cbl_field_t *odo = symbol_find_odo(parent);
           get_depending_on_value_from_odo(value64, odo);
           }
@@ -804,8 +748,8 @@ get_data_offset(const cbl_refer_t &refer, int *pflags
= NULL)
     {
     REFER("refmod refstart");
     // We have a refmod to deal with
-    static tree refstart = gg_define_variable(LONG, "..gdo_refstart",
vs_file_static);
-    static tree reflen   = gg_define_variable(LONG, "..gdo_reflen",
vs_file_static);
+    tree refstart = gg_define_variable(LONG);
+    tree reflen   = gg_define_variable(LONG);
     get_and_check_refstart_and_reflen(refstart, reflen, refer);
 
     gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, refstart)));
@@ -917,13 +861,9 @@ get_binary_value_tree(tree return_type,
                                          get_scaled_rdigits(field)));
             }
           // This will be the 128-bit value of the character sequence
-          static tree val128 = gg_define_variable(INT128,
-                                                  "..gbv_val128",
-                                                  vs_file_static);
+          tree val128 = gg_define_variable(INT128);
           // This is a pointer to the sign byte
-          static tree signp = gg_define_variable(UCHAR_P,
-                                                  "..gbv_signp",
-                                                  vs_file_static);
+          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 )
@@ -1029,9 +969,7 @@ get_binary_value_tree(tree return_type,
         {
         // Destination is too big.  We'll need to fill the high-order
bytes with
         // either 0x00 for positive numbers, or 0xFF for negative
-        static tree extension = gg_define_variable( UCHAR,
-                                                    "..gbv_extension",
-                                                    vs_file_static);
+        tree extension = gg_define_variable(UCHAR);
         if( field->attr & signable_e )
           {
           IF( gg_array_value(gg_cast(build_pointer_type(SCHAR), source)),
@@ -1103,8 +1041,7 @@ get_binary_value_tree(tree return_type,
           }
         }
       tree source_address = get_data_address(field, field_offset);
-      tree source_type = tree_type_from_size( field->data.capacity(),
-                                              field->attr & signable_e);
+      tree source_type = tree_type_from_field(field);
       if( debugging && rdigits)
         {
         gg_printf("get_binary_value bin5 rdigits: %d\n", rdigits,
NULL_TREE);
@@ -1233,10 +1170,7 @@ get_binary_value( tree value,
 tree
 tree_type_from_field(const cbl_field_t *field)
   {
-  /*  This routine is used to determine what action is taken with type of
a
-      CALL ... USING <var> and the matching PROCEDURE DIVISION USING
<var> of
-      a PROGRAM-ID or FUNCTION-ID
-      */
+  //  This routine comes up with a variable type compatible with the
field.
   tree retval;
 
   switch(field->type)
@@ -1254,21 +1188,30 @@ tree_type_from_field(const cbl_field_t *field)
     case FldNumericDisplay:
     case FldPacked:
       {
+      int digits = field->data.digits;
+      if(    (field->attr & scaled_e)
+          && field->data.rdigits < 0 )
+        {
+        // This is something like PIC 9999PPP, which means that we need a
+        // variable type that can hold those additional digits:
+        digits += -field->data.rdigits;
+        }
+
       if( field->attr & signable_e )
         {
-        if( field->data.digits > 18 )
+        if( digits > 18 )
           {
           retval = INT128;
           }
-        else if( field->data.digits > 9)
+        else if( digits > 9)
           {
           retval = LONG;
           }
-        else if( field->data.digits > 4)
+        else if( digits > 4)
           {
           retval = INT;
           }
-        else if( field->data.digits > 2)
+        else if( digits > 2)
           {
           retval = SHORT;
           }
@@ -1279,19 +1222,19 @@ tree_type_from_field(const cbl_field_t *field)
         }
       else
         {
-        if( field->data.digits > 18 )
+        if( digits > 18 )
           {
           retval = UINT128;
           }
-        else if( field->data.digits > 9)
+        else if( digits > 9)
           {
           retval = ULONG;
           }
-        else if( field->data.digits > 4)
+        else if( digits > 4)
           {
           retval = UINT;
           }
-        else if( field->data.digits > 2)
+        else if( digits > 2)
           {
           retval = USHORT;
           }
@@ -1394,6 +1337,12 @@ tree_type_from_field(const cbl_field_t *field)
   return retval;
   }
 
+tree
+tree_type_from_refer(const cbl_refer_t &refer)
+  {
+  return tree_type_from_field(refer.field);
+  }
+
 tree
 get_data_address( cbl_field_t *field,
                   tree         offset)  // Offset is SIZE_T
@@ -1513,7 +1462,7 @@ scale_by_power_of_ten(tree value,
                       bool check_for_fractional)
   {
   Analyze();
-  static tree retval = gg_define_variable(INT, "..sbpot2_retval",
vs_file_static);
+  tree retval = gg_define_variable(INT);
 
   if( check_for_fractional )
     {
@@ -1623,62 +1572,6 @@ hex_dump(tree data, size_t bytes)
     }
   }
 
-tree
-tree_type_from_size(size_t bytes, uint64_t signable)
-  {
-  tree retval = NULL_TREE;
-
-  if( signable )
-    {
-    switch( bytes )
-      {
-      case 1:
-        retval = SCHAR;
-        break;
-      case 2:
-        retval = SHORT;
-        break;
-      case 4:
-        retval = INT;
-        break;
-      case 8:
-        retval = LONG;
-        break;
-      case 16:
-        retval = INT128;
-        break;
-      default:
-        gcc_unreachable();
-        break;
-      }
-    }
-  else
-    {
-    switch( bytes )
-      {
-      case 1:
-        retval = UCHAR;
-        break;
-      case 2:
-        retval = USHORT;
-        break;
-      case 4:
-        retval = UINT;
-        break;
-      case 8:
-        retval = ULONG;
-        break;
-      case 16:
-        retval = UINT128;
-        break;
-      default:
-        gcc_unreachable();
-        break;
-      }
-    }
-  return retval;
-  }
-
 static
 bool
 refer_has_depends(const cbl_refer_t &refer, refer_type_t refer_type)
@@ -1839,18 +1732,8 @@ copy_little_endian_into_place(cbl_field_t *dest,
     // 10^(5 - 3 + 2) is 10^4, which is 10000.  Because 12345 is >=
10000, the
     // source can't fit into the destination.
 
-    // Note:  I am not trying to avoid the use of stack variables,
because I am
-    // not sure how to declare a file-static variable of unknown type.
     tree abs_value = gg_define_variable(TREE_TYPE(value));
-    IF( value, lt_op, build_int_cst_type(TREE_TYPE(value), 0) )
-      {
-      gg_assign(abs_value, gg_negate(value));
-      }
-    ELSE
-      {
-      gg_assign(abs_value, value);
-      }
-    ENDIF
+    gg_assign(abs_value, gg_abs(value));
 
     FIXED_WIDE_INT(128) power_of_ten = get_power_of_ten(
dest->data.digits
                                                         -
dest->data.rdigits
@@ -1867,12 +1750,17 @@ copy_little_endian_into_place(cbl_field_t *dest,
     }
   scale_by_power_of_ten_N(value, dest->data.rdigits - rhs_rdigits);
 
-  tree dest_type = tree_type_from_size( dest->data.capacity(),
-                                        dest->attr & signable_e);
+  // 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);
-  gg_assign(gg_indirect(gg_cast(build_pointer_type(dest_type),
dest_pointer)),
-            gg_cast(dest_type, value));
+  // 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
@@ -1948,7 +1836,7 @@ build_array_of_size_t( size_t  N,
   // This only works because it is used in but one spot.  If this routine
is
   // called twice, be careful about how the first one is used.  It's a
static
   // variable, you see.
-  static tree values_p = gg_define_variable(SIZE_T_P, "..baost_values_p",
vs_file_static);
+  tree values_p = gg_define_variable(SIZE_T_P);
   if( N )
     {
     gg_assign(  values_p,
@@ -2067,8 +1955,8 @@ refer_refmod_length(const cbl_refer_t &refer)
   {
   Analyze();
   REFER("refstart and reflen");
-  static tree refstart = gg_define_variable(LONG, "..rrl_refstart",
vs_file_static);
-  static tree reflen   = gg_define_variable(LONG, "..rrl_reflen",
vs_file_static);
+  tree refstart = gg_define_variable(LONG);
+  tree reflen   = gg_define_variable(LONG);
 
   get_and_check_refstart_and_reflen( refstart, reflen, refer);
 
@@ -2087,7 +1975,7 @@ refer_fill_depends(const cbl_refer_t &refer)
   Analyze();
   cbl_field_t *odo = symbol_find_odo(refer.field);
 
-  static tree value64 = gg_define_variable(LONG, "..rfd_value64",
vs_file_static);
+  tree value64 = gg_define_variable(LONG);
 
   get_depending_on_value(value64, refer);
 
@@ -2145,7 +2033,7 @@ refer_size(const cbl_refer_t &refer, refer_type_t
refer_type)
     }
   else
     {
-    static tree retval = gg_define_variable(SIZE_T, "..rs_retval",
vs_file_static);
+    tree retval = gg_define_variable(SIZE_T);
 
     if( !refer.field )
       {
@@ -2232,7 +2120,8 @@ refer_size_source(const cbl_refer_t &refer)
 
   // This assignment has to be here. Simply returning refer_size()
results
   // in regression testing errors.
-  static tree retval = gg_define_variable(SIZE_T, "..rss_retval",
vs_file_static);
+  ////static tree retval = gg_define_variable(SIZE_T, "..rss_retval",
vs_file_stactic);
+  tree retval = gg_define_variable(SIZE_T);
   gg_assign(retval, refer_size(refer, refer_source));
   return retval;
   }
diff --git a/gcc/cobol/genutil.h b/gcc/cobol/genutil.h
index 846c122b773..56fca1c0824 100644
--- a/gcc/cobol/genutil.h
+++ b/gcc/cobol/genutil.h
@@ -64,8 +64,6 @@ extern tree var_decl_dialects;    // void*
__gg__dialects
 
 int       get_scaled_rdigits(cbl_field_t *field);
 int       get_scaled_digits(cbl_field_t *field);
-tree      tree_type_from_digits(size_t digits, uint64_t signable);
-tree      tree_type_from_size(size_t bytes, uint64_t signable);
 
 void      get_binary_value( tree value,
                             tree rdigits,
@@ -142,6 +140,7 @@ uint64_t  get_time_nanoseconds();
 bool      is_pure_integer(const cbl_field_t *field);
 
 tree      tree_type_from_field(const cbl_field_t *field);
+tree      tree_type_from_refer(const cbl_refer_t &refer);
 
 bool      get_binary_value(tree &value, 
                      const cbl_refer_t &refer,
diff --git a/gcc/cobol/lang.opt b/gcc/cobol/lang.opt
index f72277da1ca..b134568b9dc 100644
--- a/gcc/cobol/lang.opt
+++ b/gcc/cobol/lang.opt
@@ -403,6 +403,10 @@ idirafter
 Cobol Joined Separate
 ; Documented in c.opt
 
+imultilib
+Cobol Joined Separate
+; Documented in c.opt
+
 main
 Cobol
 -main  The first program-id in the next source file is called by a
generated main() entry point.
diff --git a/gcc/cobol/lang.opt.urls b/gcc/cobol/lang.opt.urls
index 69493276ac1..db78cc00164 100644
--- a/gcc/cobol/lang.opt.urls
+++ b/gcc/cobol/lang.opt.urls
@@ -43,3 +43,6 @@ UrlSuffix(gcc/Directory-Options.html#index-isystem)
LangUrlSuffix_Fortran(gfortr
 idirafter
 UrlSuffix(gcc/Directory-Options.html#index-idirafter)
LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-idirafter)
 
+imultilib
+UrlSuffix(gcc/Directory-Options.html#index-imultilib)
LangUrlSuffix_D(gdc/Directory-Options.html#index-imultilib)
LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-imultilib)
+
diff --git a/gcc/cobol/move.cc b/gcc/cobol/move.cc
index 705d9a032d6..536d471e66b 100644
--- a/gcc/cobol/move.cc
+++ b/gcc/cobol/move.cc
@@ -92,33 +92,6 @@ is_figconst(const cbl_refer_t &sourceref)
   return is_figconst_t(sourceref.field);
   }
 
-static int
-digits_to_bytes(int digits)
-  {
-  int retval;
-  if( digits <= 2 )
-    {
-    retval = 1;
-    }
-  else if( digits <= 4 )
-    {
-    retval = 2;
-    }
-  else if( digits <= 9 )
-    {
-    retval = 4;
-    }
-  else if( digits <= 18 )
-    {
-    retval = 8;
-    }
-  else
-    {
-    retval = 16;
-    }
-  return retval;
-  }
-
 static tree
 get_reference_to_data(cbl_field_t *field)
   {
@@ -259,93 +232,11 @@ get_literalN_value(cbl_field_t *var)
   {
   // Get the literal N value from the integer var_decl
   tree retval = NULL_TREE;
-  tree var_type = tree_type_from_size(var->data.capacity(),
-                                      var->attr & signable_e);
+  tree var_type = tree_type_from_field(var);
   retval = gg_cast(var_type, var->data_decl_node);
   return retval;
   }
 
-static size_t
-get_bytes_needed(cbl_field_t *field)
-  {
-  size_t retval = 0;
-  switch(field->type)
-    {
-    case FldIndex:
-    case FldPointer:
-    case FldFloat:
-    case FldLiteralN:
-      retval = field->data.capacity();
-      break;
-
-    case FldNumericDisplay:
-      {
-      int digits;
-      if( field->attr & scaled_e && field->data.rdigits<0)
-        {
-        digits = field->data.digits + -field->data.rdigits;
-        }
-      else
-        {
-        digits = field->data.digits;
-        }
-      retval = digits_to_bytes(digits);
-      break;
-      }
-
-    case FldPacked:
-      {
-      int digits;
-      if( field->attr & scaled_e && field->data.rdigits<0)
-        {
-        digits = field->data.digits + -field->data.rdigits;
-        }
-      else
-        {
-        digits = field->data.digits;
-        }
-      if( !(field->attr & separate_e) )
-        {
-        // This is COMP-3, so there is a sign nybble.
-        digits += 1;
-        }
-      retval = (digits+1)/2;
-      break;
-      }
-
-    case FldNumericBinary:
-    case FldNumericBin5:
-      {
-      if( field->data.digits )
-        {
-        int digits;
-        if( field->attr & scaled_e && field->data.rdigits<0)
-          {
-          digits = field->data.digits + -field->data.rdigits;
-          }
-        else
-          {
-          digits = field->data.digits;
-          }
-        retval = digits_to_bytes(digits);
-        }
-      else
-        {
-        retval = field->data.capacity();
-        }
-      break;
-      }
-
-    default:
-      cbl_internal_error("%s: Knows not the variable type %s for %s",
-              __func__,
-              cbl_field_type_str(field->type),
-              field->name );
-      break;
-    }
-  return retval;
-  }
-
 static void
 get_binary_value_from_float(tree         value,
                       const cbl_refer_t &dest,
@@ -517,7 +408,7 @@ mh_source_is_literalN(cbl_refer_t &destref,
           // There are too few bytes in sourceref
           if( sourceref.field->attr & signable_e )
             {
-            static tree highbyte = gg_define_variable(UCHAR,
"..mh_litN_highbyte", vs_file_static);
+            tree highbyte = gg_define_variable(UCHAR);
             // Pick up the source byte that has the sign bit.
             gg_assign(highbyte,
 
gg_get_indirect_reference(gg_add(member(sourceref.field->var_decl_node,
@@ -576,48 +467,47 @@ mh_source_is_literalN(cbl_refer_t &destref,
 
         // For now, we are ignoring intermediates:
         assert( !(destref.field->attr & intermediate_e) );
-
-        int bytes_needed = std::max(destref.field->data.capacity(),
-                                    sourceref.field->data.capacity());
-        tree calc_type = tree_type_from_size(bytes_needed,
-                                            sourceref.field->attr &
signable_e);
-        tree dest_type = tree_type_from_size(
destref.field->data.capacity(),
-                                              destref.field->attr &
signable_e);
+        tree calc_type = tree_type_from_refer(sourceref);
+        tree dest_type = tree_type_from_refer(destref);
 
         // Pick up the source data.
         tree source = gg_define_variable(calc_type);
+        tree dest   = gg_define_variable(dest_type);
         gg_assign(source, gg_cast(calc_type,
sourceref.field->data_decl_node));
 
         // Take the absolute value, if the destination is not signable
         conditional_abs(source, destref.field);
 
+        // Cast our source to the target:
+        gg_assign(dest, gg_cast(dest_type, source));
+
         // See if it needs to be scaled:
         scale_by_power_of_ten_N(
-                     source,
-
destref.field->data.rdigits-sourceref.field->data.rdigits);
+                    dest,
+
destref.field->data.rdigits-sourceref.field->data.rdigits);
 
         if( check_for_error && size_error )
           {
           Analyzer.Message("Check to see if result fits");
           if( destref.field->data.digits )
             {
-            FIXED_WIDE_INT(128) power_of_ten =
get_power_of_ten(destref.field->data.digits);
-            IF( gg_abs(source), ge_op, wide_int_to_tree(calc_type,
-                                                        power_of_ten) )
+            FIXED_WIDE_INT(128) power_of_ten =
+
get_power_of_ten(destref.field->data.digits);
+            IF( dest, ge_op, wide_int_to_tree(calc_type, power_of_ten) )
               {
-              gg_assign(size_error, gg_bitwise_or(size_error,
integer_one_node));
+              gg_assign(size_error,
+                        gg_bitwise_or(size_error, integer_one_node));
               }
             ELSE
               ENDIF
             }
           }
 
-        Analyzer.Message("Move to destination location");
-        tree dest_location = gg_indirect(
-                    gg_cast(build_pointer_type(dest_type),
-                            gg_add(member(destref.field->var_decl_node,
"data"),
-                                   refer_offset(destref))));
-        gg_assign(dest_location, gg_cast(dest_type, source));
+        tree dest_location;
+        get_location(dest_location, destref);
+        gg_memcpy(dest_location,
+                  gg_get_address_of(dest),
+                  build_int_cst_type(SIZE_T, gg_sizeof(dest)));
         moved = true;
         break;
         }
@@ -627,7 +517,7 @@ mh_source_is_literalN(cbl_refer_t &destref,
       case FldNumericEdited:
       case FldPacked:
         {
-        static tree berror = gg_define_variable(INT, "..mh_litN_berror",
vs_file_static);
+        tree berror = gg_define_variable(INT);
         gg_assign(berror, integer_zero_node);
         SHOW_PARSE1
           {
@@ -1175,27 +1065,15 @@ mh_numeric_display( const cbl_refer_t &destref,
     charmap_t *charmap_dest   =
                        __gg__get_charmap(
destref.field->codeset.encoding);
 
-    static tree source_sign_loc  = gg_define_variable(UCHAR_P,
-                                                      "..mhnd_sign_loc",
-                                                      vs_file_static);
-    static tree dest_sign_loc = gg_define_variable(UCHAR_P,
-
"..mhnd_dest_sign_loc",
-                                                      vs_file_static);
-    static tree source_sign      = gg_define_variable(INT,
-                                                      "..mhnd_sign",
-                                                      vs_file_static);
+    tree source_sign_loc  = gg_define_variable(UCHAR_P);
+    tree dest_sign_loc = gg_define_variable(UCHAR_P);
+    tree source_sign      = gg_define_variable(INT);
     // The destination data pointer
-    static tree dest_p    = gg_define_variable( UCHAR_P,
-                                                "..mhnd_dest",
-                                                vs_file_static);
+    tree dest_p    = gg_define_variable( UCHAR_P);
     // The source data pointer
-    static tree source_p  = gg_define_variable( UCHAR_P,
-                                                "..mhnd_source",
-                                                vs_file_static);
+    tree source_p  = gg_define_variable( UCHAR_P);
     // When we need an end pointer
-    static tree source_ep = gg_define_variable( UCHAR_P,
-                                                "..mhnd_source_e",
-                                                vs_file_static);
+    tree source_ep = gg_define_variable(UCHAR_P);
 
     bool source_is_signable = sourceref.field->attr & signable_e;
     bool source_is_leading  = sourceref.field->attr & leading_e;
@@ -1537,7 +1415,6 @@ mh_little_endian( const cbl_refer_t &destref,
 
   if(     !figconst
       &&  !(destref.field->attr    & scaled_e)
-      &&  !(destref.field->attr    & (intermediate_e  ))
       &&  !(sourceref.field->attr  & (intermediate_e  ))
       &&  sourceref.field->type     != FldGroup
       &&  sourceref.field->type     != FldLiteralA
@@ -1556,14 +1433,22 @@ mh_little_endian( const cbl_refer_t &destref,
       SHOW_PARSE_END
       }
 
-    int bytes_needed = get_bytes_needed(sourceref.field);
-    tree source_type = tree_type_from_size(bytes_needed,
-                                           sourceref.field->attr
-                                                                &
signable_e) ;
-    tree source = gg_define_variable(source_type);
-
     if( sourceref.field->type == FldFloat )
       {
+      tree source = NULL_TREE;
+      switch( sourceref.field->data.capacity() )
+        {
+        case 4:
+          source = gg_define_variable(SHORT);
+          break;
+        case 8:
+          source = gg_define_variable(LONG);
+          break;
+        case 16:
+          source = gg_define_variable(INT128);
+          break;
+        }
+
       get_binary_value_from_float(source,
                                   destref,
                                   sourceref.field,
@@ -1581,6 +1466,8 @@ mh_little_endian( const cbl_refer_t &destref,
       }
     else
       {
+      tree source_type = tree_type_from_refer(sourceref);
+      tree source = gg_define_variable(source_type);
       get_binary_value( source,
                         NULL,
                         sourceref.field,
@@ -2142,18 +2029,14 @@ mh_numdisp_to_packed(const cbl_refer_t &destref,
   tree umask = build_int_cst_type(UCHAR, 0x0F);
   tree ufour = build_int_cst_type(SIZE_T,   4);
 
-  tree source_location = gg_define_variable(UCHAR_P);
-  tree dest_location   = gg_define_variable(UCHAR_P);
+  tree source_location;
+  tree dest_location;
   tree dest_p          = gg_define_variable(UCHAR_P);
   tree source_p        = gg_define_variable(UCHAR_P);
 
-  tree temp;
-
-  get_location(temp, destref);
-  gg_assign(dest_location, temp);
+  get_location(dest_location, destref);
   gg_assign(dest_p, dest_location);
-  get_location(temp, sourceref);
-  gg_assign(source_location, temp);
+  get_location(source_location, sourceref);
 
   int source_digits   = sourceref.field->data.digits;
   int source_rdigits  = sourceref.field->data.rdigits;
@@ -2453,17 +2336,13 @@ mh_packed_to_packed(const cbl_refer_t &destref,
   // in the dest.  We fiddle with the leading digits, the trailing
digits, and
   // the sign nybble as necessary.
 
-  tree source_location = gg_define_variable(UCHAR_P);
-  tree dest_location   = gg_define_variable(UCHAR_P);
+  tree source_location;
+  tree dest_location;
   tree source_sign     = gg_define_variable(UCHAR_P);
   tree dest_sign       = gg_define_variable(UCHAR_P);
-  tree temp;
-
-  get_location(temp, destref);
-  gg_assign(dest_location, temp);
 
-  get_location(temp, sourceref);
-  gg_assign(source_location, temp);
+  get_location(dest_location, destref);
+  get_location(source_location, sourceref);
 
   if( check_for_error )
     {
@@ -2799,17 +2678,14 @@ mh_packed_to_numdisp(const cbl_refer_t &destref,
   tree ufour = build_int_cst_type(SIZE_T,   4);
   tree uzero = build_int_cst_type(UCHAR,
                                   charmap->mapped_character(ascii_zero));
-  tree source_location = gg_define_variable(UCHAR_P);
-  tree dest_location   = gg_define_variable(UCHAR_P);
+  tree source_location;
+  tree dest_location;
   tree dest_p          = gg_define_variable(UCHAR_P);
   tree source_p        = gg_define_variable(UCHAR_P);
 
-  tree temp;
-  get_location(temp, destref);
-  gg_assign(dest_location, temp);
+  get_location(dest_location, destref);
   gg_assign(dest_p, dest_location);
-  get_location(temp, sourceref);
-  gg_assign(source_location, temp);
+  get_location(source_location, sourceref);
 
   // source_digits will be the number of digits extracted from the source
that
   // find their way into the destination.
@@ -3037,7 +2913,7 @@ move_helper(tree size_error,        // This is an
INT
     gg_assign(size_error, integer_zero_node);
     }
 
-  static tree stash = gg_define_variable(UCHAR_P, "..mh_stash",
vs_file_static);
+  static tree stash = gg_define_variable(UCHAR_P);
 
   tree st_data = NULL_TREE;
   tree st_size = NULL_TREE;
diff --git
a/gcc/testsuite/cobol.dg/group2/DIVIDE_binary-long_giving_remainder.cob
b/gcc/testsuite/cobol.dg/group2/DIVIDE_binary-long_giving_remainder.cob
new file mode 100644
index 00000000000..a074f4ed1d8
--- /dev/null
+++
b/gcc/testsuite/cobol.dg/group2/DIVIDE_binary-long_giving_remainder.cob
@@ -0,0 +1,26 @@
+       *> { dg-do run }
+       *> { dg-output-file
"group2/DIVIDE_binary-long_giving_remainder.out" }
+        identification              division.
+        program-id.                 prog.
+        data                        division.
+        working-storage             section.
+        01 var1     binary-long.
+        01 var2     binary-long.
+        01 Q        binary-long.
+        01 r        binary-long.
+        procedure                   division.
+            move  11 to var1 move  2 to var2
+                divide var1 by var2 giving Q remainder R
+                display Q space R
+            move -11 to var1 move  2 to var2
+                divide var1 by var2 giving Q remainder R
+                display Q space R
+            move  11 to var1 move -2 to var2
+                divide var1 by var2 giving Q remainder R
+                display Q space R
+            move -11 to var1 move -2 to var2
+                divide var1 by var2 giving Q remainder R
+                display Q space R
+            goback.
+        end program                 prog.
+
diff --git
a/gcc/testsuite/cobol.dg/group2/DIVIDE_binary-long_giving_remainder.out
b/gcc/testsuite/cobol.dg/group2/DIVIDE_binary-long_giving_remainder.out
new file mode 100644
index 00000000000..50e20e8a1e0
--- /dev/null
+++
b/gcc/testsuite/cobol.dg/group2/DIVIDE_binary-long_giving_remainder.out
@@ -0,0 +1,5 @@
++0000000005 +0000000001
+-0000000005 -0000000001
+-0000000005 +0000000001
++0000000005 -0000000001
+
diff --git
a/gcc/testsuite/cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.co
b
b/gcc/testsuite/cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.co
b
new file mode 100644
index 00000000000..7b605f058df
--- /dev/null
+++
b/gcc/testsuite/cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.co
b
@@ -0,0 +1,26 @@
+       *> { dg-do run }
+       *> { dg-output-file
"group2/DIVIDE_numeric-display_giving_remainder.out" }
+        identification              division.
+        program-id.                 prog.
+        data                        division.
+        working-storage             section.
+        01 var1     pic s999.
+        01 var2     pic s999.
+        01 Q        pic s999.
+        01 r        pic s999.
+        procedure                   division.
+            move  11 to var1 move  2 to var2
+                divide var1 by var2 giving Q remainder R
+                display Q space R
+            move -11 to var1 move  2 to var2
+                divide var1 by var2 giving Q remainder R
+                display Q space R
+            move  11 to var1 move -2 to var2
+                divide var1 by var2 giving Q remainder R
+                display Q space R
+            move -11 to var1 move -2 to var2
+                divide var1 by var2 giving Q remainder R
+                display Q space R
+            goback.
+        end program                 prog.
+
diff --git
a/gcc/testsuite/cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.ou
t
b/gcc/testsuite/cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.ou
t
new file mode 100644
index 00000000000..1016fd0d622
--- /dev/null
+++
b/gcc/testsuite/cobol.dg/group2/DIVIDE_numeric-display_giving_remainder.ou
t
@@ -0,0 +1,5 @@
++005 +001
+-005 -001
+-005 +001
++005 -001
+
diff --git
a/gcc/testsuite/cobol.dg/group2/GCC_125616_RT3601_-_IBM_incorrect_DISPLAY_
of_COMP-1_COMP-2_float.cob
b/gcc/testsuite/cobol.dg/group2/GCC_125616_RT3601_-_IBM_incorrect_DISPLAY_
of_COMP-1_COMP-2_float.cob
new file mode 100644
index 00000000000..0989b212c9c
--- /dev/null
+++
b/gcc/testsuite/cobol.dg/group2/GCC_125616_RT3601_-_IBM_incorrect_DISPLAY_
of_COMP-1_COMP-2_float.cob
@@ -0,0 +1,20 @@
+       *> { dg-do run }
+       *> { dg-options "-dialect ibm" }
+
+       IDENTIFICATION DIVISION.
+       PROGRAM-ID. FLTDISP.
+       DATA DIVISION.
+       WORKING-STORAGE SECTION.
+       01  F1 COMP-1 VALUE 1.5.
+       01  F2 COMP-1 VALUE 0.1.
+       01  F3 COMP-1 VALUE -2.75.
+       01  F4 COMP-1 VALUE 1500.
+       01  D1 COMP-2 VALUE 2.71828.
+       PROCEDURE DIVISION.
+           DISPLAY F1
+           DISPLAY F2
+           DISPLAY F3
+           DISPLAY F4
+           DISPLAY D1
+           STOP RUN.
+
diff --git
a/gcc/testsuite/cobol.dg/group2/PR39_RT3573_-_Parser_issue_w_concat._sourc
e_lines.cob
b/gcc/testsuite/cobol.dg/group2/PR39_RT3573_-_Parser_issue_w_concat._sourc
e_lines.cob
new file mode 100644
index 00000000000..124a73c41bc
--- /dev/null
+++
b/gcc/testsuite/cobol.dg/group2/PR39_RT3573_-_Parser_issue_w_concat._sourc
e_lines.cob
@@ -0,0 +1,10 @@
+      *> { dg-do compile }
+
+            >>SOURCE FORMAT IS FREE
+        IDENTIFICATION DIVISION.  PROGRAM-ID. issue4.  DATA DIVISION.
+        WORKING-STORAGE SECTION.
+        1 hello-string PIC X(12) VALUE "Hello string".
+        PROCEDURE DIVISION.
+        DISPLAY hello-string.
+        EXIT PROGRAM.
+
diff --git a/libgcobol/gmath.cc b/libgcobol/gmath.cc
index e2a25757dea..19ea3702927 100644
--- a/libgcobol/gmath.cc
+++ b/libgcobol/gmath.cc
@@ -363,11 +363,12 @@ typedef struct int128
     };
   }int128;
 
+
 static int
 multiply_int256_by_int64(int256 &product, const uint64_t multiplier)
   {
   // Typical use of this routine is multiplying a temporary value by
-  // a factor of ten.  This is effectively left-shifting by decimal
+  // a power of ten.  This is effectively left-shifting by decimal
   // digits.  See scale_int256_by_digits
   uint64_t overflows[5] = {};
   int128 temp;
@@ -1531,6 +1532,21 @@ int256_as_decimal(int256 val)
   memset(ach, 0, sizeof(ach));
   strcpy(ach, "0");
   int index = 0;
+  bool is_negative = false;
+
+  if( val.data[31] & 0x80 )
+    {
+    // One's complement:
+    val.i128[0] = ~val.i128[0];
+    val.i128[1] = ~val.i128[1];
+    // Two's complement:
+    if( ++val.i128[0] == 0 )
+      {
+      ++val.i128[1];
+      }
+    is_negative = true;
+    }
+
   while(val.i128[0] || val.i128[1])
     {
     int256 before;
@@ -1543,6 +1559,10 @@ int256_as_decimal(int256 val)
     ach[index++] = digit + '0';
     divide_int256_by_int64(val, 10);
     }
+  if( is_negative )
+    {
+    ach[index++] = '-';
+    }
   if( !index )
     {
     index = 1;
@@ -2081,6 +2101,7 @@ __gg__dividef45(cbl_arith_format_t ,
                             compute_error);
 
     *compute_error |= squeeze_int256(quotient, quotient_rdigits);
+
     if( !*compute_error )
       {
       // We are going to need the unrounded quotient to calculate the
remainder
@@ -2154,6 +2175,11 @@ __gg__dividef45(cbl_arith_format_t ,
         temp_rdigits = unrounded_quotient_digits + divisor_rdigits;
 
         int256 odividend = {};
+        if( dividend < 0 )
+          {
+          memset(&odividend, 0xFF, sizeof(odividend));
+          }
+
         memcpy(&odividend, &dividend, sizeof(dividend));
 
         // We need to line up the rdigits so that we can subtract temp
from
-- 
2.34.1

Reply via email to