> -----Original Message-----
> From: Jakub Jelinek <ja...@redhat.com>
> Sent: Tuesday, March 25, 2025 19:49
> To: Robert Dubner <rdub...@symas.com>; James K. Lowden
> <jklow...@cobolworx.com>; Richard Biener <rguent...@suse.de>
> Cc: gcc-patches@gcc.gnu.org
> Subject: [PATCH] cobol: Get rid of __int128 uses in the COBOL FE
> [PR119242]
> 
> Hi!
> 
> 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.
> 
> Tested on x86_64-linux with make check-cobol, could you please test this
> on UAT/NIST?

I took a minute to apply the patch and run the tests.  Ten of the UAT
tests fail; they are the ones that test the ROUNDED clause.

It's 00:30 local time here, so I am not going to look into it now.  But
here is a simple case so that you have something to chew on while I am
getting my beauty sleep:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. prog.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  N                PIC S9.
       PROCEDURE DIVISION.
           COMPUTE N ROUNDED MODE AWAY-FROM-ZERO = -2.51
           DISPLAY "N should be -3"
           DISPLAY "N        is " N
           GOBACK.
           END PROGRAM prog.

        N should be -3
        N        is +1

> 
> 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
>       * cobol/genutil.h (get_power_of_ten): Remove #pragma GCC
diagnostic
>       around declaration.
>       * cobol/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.
>       * cobol/genutil.cc (get_power_of_ten): Remove #pragma GCC
diagnostic
>       before the definition.
> 
> --- gcc/cobol/genutil.h.jj    2025-03-25 21:14:48.448384925 +0100
> +++ gcc/cobol/genutil.h       2025-03-25 21:19:24.358620134 +0100
> @@ -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);
> --- gcc/cobol/genapi.cc.jj    2025-03-25 21:11:06.767409766 +0100
> +++ gcc/cobol/genapi.cc       2025-03-25 21:22:28.038113833 +0100
> @@ -3798,16 +3798,13 @@ psa_FldLiteralN(struct cbl_field_t *fiel
>    // 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 *fiel
> 
>      // 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,15 @@ psa_FldLiteralN(struct cbl_field_t *fiel
> 
>      if( capacity < 16 && (field->attr & signable_e) )
>        {
> -      if( value < 0 && (((pvalue[capacity-1] & 0x80) == 0 )))
> +      if( wi::neg_p (value)
> +          && (value & wi::set_bit_in_zero<FIXED_WIDE_INT(128)>(capacity
*
> 8
> +                                                               - 1)) !=
0
> )
>          {
>          capacity *= 2;
>          }
> -      else if( value >= 0 && (((pvalue[capacity-1] & 0x80) == 0x80 )))
> +      else if( !wi::neg_p (value)
> +               && (value &
> wi::set_bit_in_zero<FIXED_WIDE_INT(128)>(capacity * 8
> +                                                                    -
1))
> == 0 )
>          {
>          capacity *= 2;
>          }
> @@ -3964,86 +3965,15 @@ psa_FldLiteralN(struct cbl_field_t *fiel
> 
>    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 +13669,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 +13941,6 @@ mh_source_is_literalN(cbl_refer_t &destr
>      }
>    return moved;
>    }
> -#pragma GCC diagnostic pop
> 
>  static
>  tree float_type_of(int n)
> @@ -15245,8 +15172,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 +15247,6 @@ binary_initial_from_float128(cbl_field_t
> 
>    return retval;
>    }
> -#pragma GCC diagnostic pop
> 
> 
>  static void
> --- gcc/cobol/genutil.cc.jj   2025-03-25 21:14:52.450330315 +0100
> +++ gcc/cobol/genutil.cc      2025-03-25 21:19:08.743833202 +0100
> @@ -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)
>    {
> 
>       Jakub

Reply via email to