From e9400aaa6fb4be5defef45a2d14d830b77800d51 Mon Sep 17 00:00:00 2001
From: Bob Dubner <rdubner@symas.com>
Date: Mon, 1 Jan 2024 14:12:23 -0500
Subject: [PATCH] Handles 128-bit and 64-bit BY VALUE

---
 gcc/cobol/genapi.cc    | 95 ++++++++++++++++++++++++++++++------------
 libgcobol/libgcobol.cc | 12 ++----
 2 files changed, 73 insertions(+), 34 deletions(-)

diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index a65b0d1a6ea6..7021bbc7a419 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -5433,7 +5433,10 @@ parser_division(cbl_division_t division,
 
       char ach[2*sizeof(cbl_name_t)];
       sprintf(ach, "_p_%s", args[i].refer.field->name);
-      chain_parameter_to_function(current_function->function_decl, VOID_P, ach);
+
+      size_t nchars = 0;
+      tree par_type = tree_type_from_field_type(args[i].refer.field, nchars);
+      chain_parameter_to_function(current_function->function_decl, par_type, ach);
       }
 
     if( nusing )
@@ -5501,13 +5504,50 @@ parser_division(cbl_division_t division,
 
         if( args[i].crv == by_value_e )
           {
-          // 'parameter' is the 64-bit value that was placed on the stack
+          // 'parameter' is the 64-bit or 128-bit value that was placed on the stack
+
           cbl_field_t *new_var = args[i].refer.field;
-          
+
+          size_t nbytes;
+          tree_type_from_field_type(new_var, nbytes);
+          tree parm = gg_define_variable(INT128);
+
+          if( nbytes <= 8 )
+            {
+            // Our input is a 64-bit number
+            if( new_var->attr & signable_e )
+              {
+              IF( gg_bitwise_and( gg_cast(SIZE_T, parameter),
+                                  build_int_cst_type(SIZE_T, 0x8000000000000000ULL)),
+                  ne_op,
+                  gg_cast(SIZE_T, integer_zero_node) )
+                {
+                // Our input is a negative number
+                gg_assign(parm, gg_cast(INT128, integer_minus_one_node));
+                }
+              ELSE
+                {
+                // Our input is a positive number
+                gg_assign(parm, gg_cast(INT128, integer_zero_node));
+                }
+              ENDIF
+              }
+            else
+              {
+              // This is a 64-bit positive number:
+              gg_assign(parm, gg_cast(INT128, integer_zero_node));
+              }
+            }
+          // At this point, parm has been set to 0 or -1
+
+          gg_memcpy(gg_get_address_of(parm),
+                    gg_get_address_of(parameter),
+                    build_int_cst_type(SIZE_T, nbytes));
+
           tree array_type = build_array_type_nelts(UCHAR, new_var->data.capacity);
           tree data_decl_node = gg_define_variable( array_type,
-                                                          NULL,
-                                                          vs_stack);
+                                                    NULL,
+                                                    vs_stack);
           gg_assign( member(new_var->var_decl_node, "data"),
                             gg_get_address_of(data_decl_node) );
 
@@ -5516,7 +5556,7 @@ parser_division(cbl_division_t division,
                   "__gg__assign_value_from_stack",
                   2,
                   gg_get_address_of(new_var->var_decl_node),
-                  parameter);
+                  parm);
           }
         else
           {
@@ -10541,7 +10581,7 @@ parser_call(   cbl_refer_t name,
     int  *allocated = NULL;
     if(narg)
       {
-      arguments = (tree *)xmalloc(narg * sizeof(tree));
+      arguments = (tree *)xmalloc(2*narg * sizeof(tree));
       allocated = (int * )xmalloc(narg * sizeof(int));
       }
 
@@ -10550,6 +10590,7 @@ parser_call(   cbl_refer_t name,
               build_int_cst_type(INT, narg));
 
     // Put the arguments onto the stack:
+    size_t arg_count = 0;
     for( size_t i=0; i<narg; i++ )
       {
       allocated[i] = 0;
@@ -10589,7 +10630,7 @@ parser_call(   cbl_refer_t name,
 
           // Pass the pointer to the data location, so that the called program
           // can both access and change the data.
-          arguments[i] = location;
+          arguments[arg_count] = location;
 
           // BY REFERENCE variables might be going into an ANY LENGTH
           // linkage variable in the called program.  So, just in case, we need
@@ -10610,12 +10651,12 @@ parser_call(   cbl_refer_t name,
           // We'll free this copy after the called program returns.
 
           // Allocate the memory, and make the copy:
-          arguments[i] = gg_define_char_star();
+          arguments[arg_count] = gg_define_char_star();
           allocated[i] = 1;
-          gg_assign(arguments[i], gg_malloc(length) ) ;
-          gg_memcpy(arguments[i], location, length);
+          gg_assign(arguments[arg_count], gg_malloc(length) ) ;
+          gg_memcpy(arguments[arg_count], location, length);
 
-          //gg_printf(">>>>>Calling %ld location is %p\n", build_int_cst_type(SIZE_T, i), arguments[i], NULL_TREE);
+          //gg_printf(">>>>>Calling %ld location is %p\n", build_int_cst_type(SIZE_T, i), arguments[arg_count], NULL_TREE);
 
           // BY CONTENT variables might be going into an ANY LENGTH
           // linkage variable in the called program.  So, just in case, we need
@@ -10630,31 +10671,33 @@ parser_call(   cbl_refer_t name,
           // necessary.
 
           if( (args[i].refer.field && args[i].refer.field->data.digits > 18) 
-              || (args[i].refer.field && args[i].refer.field->type == FldFloat 
+              || (   args[i].refer.field 
+                  && args[i].refer.field->type == FldFloat 
                   && args[i].refer.field->data.capacity == 16 ) )
             {
-            arguments[i] = gg_define_variable(INT128);
-            gg_assign(arguments[i],
+            arguments[arg_count] = gg_define_variable(INT128);
+            gg_assign(arguments[arg_count],
                       gg_cast(INT128,
                               gg_call_expr(
-                            INT128,
-                            "__gg__fetch_call_by_value_value",
-                            1,
-                            gg_get_address_of(args[i].refer.refer_decl_node))));
+                              INT128,
+                              "__gg__fetch_call_by_value_value",
+                              1,
+                              gg_get_address_of(args[i].refer.refer_decl_node))));
             }
           else
             {
-            arguments[i] = gg_define_size_t();
-            gg_assign(arguments[i],
+            arguments[arg_count] = gg_define_size_t();
+            gg_assign(arguments[arg_count],
                       gg_cast(SIZE_T,
                               gg_call_expr(
-                            INT128,
-                            "__gg__fetch_call_by_value_value",
-                            1,
-                            gg_get_address_of(args[i].refer.refer_decl_node))));
+                              INT128,
+                              "__gg__fetch_call_by_value_value",
+                              1,
+                              gg_get_address_of(args[i].refer.refer_decl_node))));
             }
           break;
         }
+      arg_count += 1;
       }
 
     gg_call(VOID,
@@ -10664,7 +10707,7 @@ parser_call(   cbl_refer_t name,
 
     tree call_expr = gg_call_expr_list( returned_value_type,
                                         function_handle,
-                                        narg,
+                                        arg_count,
                                         arguments );
     tree returned_value;
     if( returned.field )
diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc
index 7c6bab358aef..9c335bbee32f 100644
--- a/libgcobol/libgcobol.cc
+++ b/libgcobol/libgcobol.cc
@@ -8192,7 +8192,7 @@ __gg__fetch_call_by_value_value(cblc_refer_t *var)
 
 extern "C"
 void
-__gg__assign_value_from_stack(cblc_field_t *dest, size_t parameter)
+__gg__assign_value_from_stack(cblc_field_t *dest, __int128 parameter)
   {
   switch(dest->type)
     {
@@ -8204,10 +8204,6 @@ __gg__assign_value_from_stack(cblc_field_t *dest, size_t parameter)
         {
         warnx("%s is not valid for BY VALUE", dest->name);
         exit(1);
-        memset(dest->data, internal_space, dest->capacity);
-        // A single 8-bit character was placed in the 64-bit entry on the
-        // stack.
-        *(char *)dest->data = *(char *)parameter;
         }
       break;
 
@@ -8216,15 +8212,15 @@ __gg__assign_value_from_stack(cblc_field_t *dest, size_t parameter)
       switch(dest->capacity)
         {
         case 4:
-          *(float *)(dest->data) = *(float *)parameter;
+          *(float *)(dest->data) = *(float *)&parameter;
           break;
 
         case 8:
-          *(double *)(dest->data) = *(double *)parameter;
+          *(double *)(dest->data) = *(double *)&parameter;
           break;
 
         case 16:
-          *(_Float128 *)(dest->data) = *(_Float128 *)parameter;
+          *(_Float128 *)(dest->data) = *(_Float128 *)&parameter;
           break;
         }
       break;
-- 
GitLab