https://gcc.gnu.org/g:5e897d7e954439c4f0aea1ffa0c18bbea27e3373

commit r15-8936-g5e897d7e954439c4f0aea1ffa0c18bbea27e3373
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Wed Mar 26 20:07:09 2025 +0100

    cobol: Get rid of __int128 uses in the COBOL FE [PR119242]
    
    The following patch changes some remaining __int128 uses in the FE
    into FIXED_WIDE_INT(128), i.e. emulated 128-bit integral type.
    The use of wide_int_to_tree directly from that rather than going through
    build_int_cst_type means we don't throw away the upper 64 bits of the
    values, so the emitting of constants needing full 128 bits can be greatly
    simplied.
    Plus all the #pragma GCC diagnostic ignored "-Wpedantic" spots aren't
    needed, we don't use the _Float128/__int128 types directly in the FE
    anymore.
    
    Note, PR119241/PR119242 bugs are still not fully fixed, I think the
    remaining problem is that several FE sources include
    ../../libgcobol/libgcobol.h and that header declares various APIs with
    __int128 and _Float128 types, so trying to build a cross-compiler on a host
    without __int128 and _Float128 will still fail miserably.
    I believe none of those APIs are actually used by the FE, so the question is
    what the FE needs from libgcobol.h and whether the rest could be wrapped
    with #ifndef IN_GCC or #ifndef IN_GCC_FRONTEND or something similar
    (those 2 macros are predefined when compiling the FE files).
    
    2025-03-26  Jakub Jelinek  <ja...@redhat.com>
    
            PR cobol/119242
            * genutil.h (get_power_of_ten): Remove #pragma GCC diagnostic
            around declaration.
            * genapi.cc (psa_FldLiteralN): Change type of value from
            __int128 to FIXED_WIDE_INT(128).  Remove #pragma GCC diagnostic
            around the declaration.  Use wi::min_precision to determine
            minimum unsigned precision of the value.  Use wi::neg_p instead
            of value < 0 tests and wi::set_bit_in_zero<FIXED_WIDE_INT(128)>
            to build sign bit.  Handle field->data.capacity == 16 like
            1, 2, 4 and 8, use wide_int_to_tree instead of build_int_cst.
            (mh_source_is_literalN): Remove #pragma GCC diagnostic around
            the definition.
            (binary_initial_from_float128): Likewise.
            * genutil.cc (get_power_of_ten): Remove #pragma GCC diagnostic
            before the definition.

Diff:
---
 gcc/cobol/genapi.cc  | 118 +++++++++------------------------------------------
 gcc/cobol/genutil.cc |   3 --
 gcc/cobol/genutil.h  |   3 --
 3 files changed, 20 insertions(+), 104 deletions(-)

diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 8a58423264e4..dc0bb79e1532 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -3798,16 +3798,13 @@ psa_FldLiteralN(struct cbl_field_t *field )
   // We are constructing a completely static constant structure, based on the
   // text string in .initial
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpedantic"
-  __int128 value = 0;
-#pragma GCC diagnostic pop
+  FIXED_WIDE_INT(128) value = 0;
 
   do
     {
     // This is a false do{}while, to isolate the variables:
 
-    // We need to convert data.initial to an __int128 value
+    // We need to convert data.initial to an FIXED_WIDE_INT(128) value
     char *p = const_cast<char *>(field->data.initial);
     int sign = 1;
     if( *p == '-' )
@@ -3903,24 +3900,24 @@ psa_FldLiteralN(struct cbl_field_t *field )
 
     // We now need to calculate the capacity.
 
-    unsigned char *pvalue = (unsigned char *)&value;
+    unsigned int min_prec = wi::min_precision(value, UNSIGNED);
     int capacity;
-    if( *(uint64_t*)(pvalue + 8) )
+    if( min_prec > 64 )
       {
       // Bytes 15 through 8 are non-zero
       capacity = 16;
       }
-    else if( *(uint32_t*)(pvalue + 4) )
+    else if( min_prec > 32 )
       {
       // Bytes 7 through 4 are non-zero
       capacity = 8;
       }
-    else if( *(uint16_t*)(pvalue + 2) )
+    else if( min_prec > 16 )
       {
       // Bytes 3 and 2
       capacity = 4;
       }
-    else if( pvalue[1] )
+    else if( min_prec > 8 )
       {
       // Byte 1 is non-zero
       capacity = 2;
@@ -3940,11 +3937,13 @@ psa_FldLiteralN(struct cbl_field_t *field )
 
     if( capacity < 16 && (field->attr & signable_e) )
       {
-      if( value < 0 && (((pvalue[capacity-1] & 0x80) == 0 )))
+      FIXED_WIDE_INT(128) mask
+        = wi::set_bit_in_zero<FIXED_WIDE_INT(128)>(capacity * 8 - 1);
+      if( wi::neg_p (value) && (value & mask) == 0 )
         {
         capacity *= 2;
         }
-      else if( value >= 0 && (((pvalue[capacity-1] & 0x80) == 0x80 )))
+      else if( !wi::neg_p (value) && (value & mask) != 0 )
         {
         capacity *= 2;
         }
@@ -3964,86 +3963,15 @@ psa_FldLiteralN(struct cbl_field_t *field )
 
   tree var_type;
 
-  if( field->data.capacity == 16 )
-    {
-    /*  GCC-13 has no provision for an int128 constructor.  So, we use a
-        union for our necessary __int128.
-
-        typedef union cblc_int128_t
-            {
-            unsigned char array16[16];
-            __uint128     uval128;
-            __int128      sval128;
-            } cblc_int128_t;
-
-      We build a constructor for the array16[], and then we use that
-      constructor in the constructor for the union.
-      */
-
-    // Build the constructor for array16
-    tree array16_type                   = build_array_type_nelts(UCHAR, 16);
-    tree array_16_constructor           = make_node(CONSTRUCTOR);
-    TREE_TYPE(array_16_constructor)     = array16_type;
-    TREE_STATIC(array_16_constructor)   = 1;
-    TREE_CONSTANT(array_16_constructor) = 1;
-
-    for(int i=0; i<16; i++)
-      {
-      CONSTRUCTOR_APPEND_ELT( CONSTRUCTOR_ELTS(array_16_constructor),
-                              build_int_cst_type(INT, i),
-                              build_int_cst_type(UCHAR,
-                                                 ((unsigned char 
*)&value)[i]));
-      }
-
-    // The array16 constructor is ready to be used
-
-    // So, we need a constructor for the union:
-    // Now we create the union:
-    var_type = cblc_int128_type_node;
-
-    tree union_constructor            = make_node(CONSTRUCTOR);
-    TREE_TYPE(union_constructor)      = var_type;
-    TREE_STATIC(union_constructor)    = 1;
-    TREE_CONSTANT(union_constructor)  = 1;
-
-    // point next_field to the first field of the union, and
-    // set the value to be the table constructor
-    tree next_field = TYPE_FIELDS(var_type);
-    CONSTRUCTOR_APPEND_ELT( CONSTRUCTOR_ELTS(union_constructor),
-                            next_field,
-                            array_16_constructor );
-
-    tree new_var_decl = gg_define_variable( var_type,
-                                            base_name,
-                                            vs_static);
-    DECL_INITIAL(new_var_decl) = union_constructor;
-
-    field->data_decl_node = member(new_var_decl, "sval128");
-    TREE_READONLY(field->data_decl_node) = 1;
-    TREE_CONSTANT(field->data_decl_node) = 1;
-
-    // Convert the compile-time data.value to a run-time variable decl node:
-    sprintf(id_string, ".%ld", ++our_index);
-    strcpy(base_name, field->name);
-    strcat(base_name, id_string);
-    field->literal_decl_node = gg_define_variable(DOUBLE, id_string, 
vs_static);
-    TREE_READONLY(field->literal_decl_node) = 1;
-    TREE_CONSTANT(field->literal_decl_node) = 1;
-    tree initer = fold_convert (DOUBLE, field->data.value_of());
-    DECL_INITIAL(field->literal_decl_node) = initer;
-
-    }
-  else
-    {
-    // The value is 1, 2, 4, or 8 bytes, so an ordinary constructor can be 
used.
-    var_type = tree_type_from_size( field->data.capacity,
-                                    field->attr & signable_e);
-    tree new_var_decl = gg_define_variable( var_type,
-                                            base_name,
-                                            vs_static);
-    DECL_INITIAL(new_var_decl) = build_int_cst_type(var_type, value);
-    field->data_decl_node = new_var_decl;
-    }
+  // 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);
+  tree new_var_decl = gg_define_variable( var_type,
+                                          base_name,
+                                          vs_static);
+  DECL_INITIAL(new_var_decl) = wide_int_to_tree(var_type, value);
+  field->data_decl_node = new_var_decl;
   }
 
 static void
@@ -13739,8 +13667,6 @@ mh_identical(cbl_refer_t &destref,
   return moved;
   }
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpedantic"
 static bool
 mh_source_is_literalN(cbl_refer_t &destref,
                       cbl_refer_t &sourceref,
@@ -14013,7 +13939,6 @@ mh_source_is_literalN(cbl_refer_t &destref,
     }
   return moved;
   }
-#pragma GCC diagnostic pop
 
 static
 tree float_type_of(int n)
@@ -15245,8 +15170,6 @@ real_powi10 (uint32_t x)
   return pow10;
 }
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpedantic"
 char *
 binary_initial_from_float128(cbl_field_t *field, int rdigits,
                              REAL_VALUE_TYPE value)
@@ -15322,7 +15245,6 @@ binary_initial_from_float128(cbl_field_t *field, int 
rdigits,
 
   return retval;
   }
-#pragma GCC diagnostic pop
 
 
 static void
diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc
index 755c87153d70..509f8d23f3c2 100644
--- a/gcc/cobol/genutil.cc
+++ b/gcc/cobol/genutil.cc
@@ -1419,9 +1419,6 @@ get_data_address( cbl_field_t *field,
     }
   }
 
-// Ignore pedantic because we know 128-bit computation is not ISO C++14. 
-#pragma GCC diagnostic ignored "-Wpedantic"
-
 FIXED_WIDE_INT(128)
 get_power_of_ten(int n)
   {
diff --git a/gcc/cobol/genutil.h b/gcc/cobol/genutil.h
index 566ce776e7a7..6ef4dee5aadf 100644
--- a/gcc/cobol/genutil.h
+++ b/gcc/cobol/genutil.h
@@ -104,10 +104,7 @@ void      get_binary_value( tree value,
 tree      get_data_address( cbl_field_t *field,
                             tree         offset);
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpedantic"
 FIXED_WIDE_INT(128) get_power_of_ten(int n);
-#pragma GCC diagnostic pop
 void      scale_by_power_of_ten_N(tree value,
                                 int N,
                                 bool check_for_fractional = false);

Reply via email to