On Tue, 5 Mar 2024, Jakub Jelinek wrote:

> Hi!
> 
> The following patch adds support for BIT_FIELD_REF lowering with
> large/huge _BitInt lhs.  BIT_FIELD_REF requires mode argument first
> operand, so the operand shouldn't be any huge _BitInt.
> If we only access limbs from inside of BIT_FIELD_REF using constant
> indexes, we can just create a new BIT_FIELD_REF to extract the limb,
> but if we need to use variable index in a loop, I'm afraid we need
> to spill it into memory, which is what the following patch does.

:/

If it's only ever "small" _BitInt and we'd want to optimize we could
fully unroll the loop at code generation time and thus avoid the
variable indices?  You could also lower the BIT_FIELD_REF to
variable shifts & masking I suppose.

Not sure if it's worth the trouble though.

> If there is some bitwise type for the extraction, it extracts just
> what we need and not more than that, otherwise it spills the whole
> first argument of BIT_FIELD_REF and uses MEM_REF with an offset
> with VIEW_CONVERT_EXPR around it.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Thanks,
Richard.

> 2024-03-05  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR middle-end/114157
>       * gimple-lower-bitint.cc: Include stor-layout.h.
>       (mergeable_op): Return true for BIT_FIELD_REF.
>       (struct bitint_large_huge): Declare handle_bit_field_ref method.
>       (bitint_large_huge::handle_bit_field_ref): New method.
>       (bitint_large_huge::handle_stmt): Use it for BIT_FIELD_REF.
> 
>       * gcc.dg/bitint-98.c: New test.
>       * gcc.target/i386/avx2-pr114157.c: New test.
>       * gcc.target/i386/avx512f-pr114157.c: New test.
> 
> --- gcc/gimple-lower-bitint.cc.jj     2024-03-04 11:14:57.450288563 +0100
> +++ gcc/gimple-lower-bitint.cc        2024-03-04 18:51:06.833008534 +0100
> @@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.
>  #include "tree-cfgcleanup.h"
>  #include "tree-switch-conversion.h"
>  #include "ubsan.h"
> +#include "stor-layout.h"
>  #include "gimple-lower-bitint.h"
>  
>  /* Split BITINT_TYPE precisions in 4 categories.  Small _BitInt, where
> @@ -212,6 +213,7 @@ mergeable_op (gimple *stmt)
>      case BIT_NOT_EXPR:
>      case SSA_NAME:
>      case INTEGER_CST:
> +    case BIT_FIELD_REF:
>        return true;
>      case LSHIFT_EXPR:
>        {
> @@ -435,6 +437,7 @@ struct bitint_large_huge
>    tree handle_plus_minus (tree_code, tree, tree, tree);
>    tree handle_lshift (tree, tree, tree);
>    tree handle_cast (tree, tree, tree);
> +  tree handle_bit_field_ref (tree, tree);
>    tree handle_load (gimple *, tree);
>    tree handle_stmt (gimple *, tree);
>    tree handle_operand_addr (tree, gimple *, int *, int *);
> @@ -1685,6 +1688,86 @@ bitint_large_huge::handle_cast (tree lhs
>    return NULL_TREE;
>  }
>  
> +/* Helper function for handle_stmt method, handle a BIT_FIELD_REF.  */
> +
> +tree
> +bitint_large_huge::handle_bit_field_ref (tree op, tree idx)
> +{
> +  if (tree_fits_uhwi_p (idx))
> +    {
> +      if (m_first)
> +     m_data.safe_push (NULL);
> +      ++m_data_cnt;
> +      unsigned HOST_WIDE_INT sz = tree_to_uhwi (TYPE_SIZE (m_limb_type));
> +      tree bfr = build3 (BIT_FIELD_REF, m_limb_type,
> +                      TREE_OPERAND (op, 0),
> +                      TYPE_SIZE (m_limb_type),
> +                      size_binop (PLUS_EXPR, TREE_OPERAND (op, 2),
> +                                  bitsize_int (tree_to_uhwi (idx) * sz)));
> +      tree r = make_ssa_name (m_limb_type);
> +      gimple *g = gimple_build_assign (r, bfr);
> +      insert_before (g);
> +      tree type = limb_access_type (TREE_TYPE (op), idx);
> +      if (!useless_type_conversion_p (type, m_limb_type))
> +     r = add_cast (type, r);
> +      return r;
> +    }
> +  tree var;
> +  if (m_first)
> +    {
> +      unsigned HOST_WIDE_INT sz = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (op)));
> +      machine_mode mode;
> +      tree type, bfr;
> +      if (bitwise_mode_for_size (sz).exists (&mode)
> +       && known_eq (GET_MODE_BITSIZE (mode), sz))
> +     type = bitwise_type_for_mode (mode);
> +      else
> +     {
> +       mode = VOIDmode;
> +       type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (op, 0)));
> +     }
> +      if (TYPE_ALIGN (type) < TYPE_ALIGN (TREE_TYPE (op)))
> +     type = build_aligned_type (type, TYPE_ALIGN (TREE_TYPE (op)));
> +      var = create_tmp_var (type);
> +      TREE_ADDRESSABLE (var) = 1;
> +      gimple *g;
> +      if (mode != VOIDmode)
> +     {
> +       bfr = build3 (BIT_FIELD_REF, type, TREE_OPERAND (op, 0),
> +                     TYPE_SIZE (type), TREE_OPERAND (op, 2));
> +       g = gimple_build_assign (make_ssa_name (type),
> +                                BIT_FIELD_REF, bfr);
> +       gimple_set_location (g, m_loc);
> +       gsi_insert_after (&m_init_gsi, g, GSI_NEW_STMT);
> +       bfr = gimple_assign_lhs (g);
> +     }
> +      else
> +     bfr = TREE_OPERAND (op, 0);
> +      g = gimple_build_assign (var, bfr);
> +      gimple_set_location (g, m_loc);
> +      gsi_insert_after (&m_init_gsi, g, GSI_NEW_STMT);
> +      if (mode == VOIDmode)
> +     {
> +       unsigned HOST_WIDE_INT nelts
> +         = CEIL (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (op))), limb_prec);
> +       tree atype = build_array_type_nelts (m_limb_type, nelts);
> +       var = build2 (MEM_REF, atype, build_fold_addr_expr (var),
> +                     build_int_cst (build_pointer_type (type),
> +                                    tree_to_uhwi (TREE_OPERAND (op, 2))
> +                                    / BITS_PER_UNIT));
> +     }
> +      m_data.safe_push (var);
> +    }
> +  else
> +    var = unshare_expr (m_data[m_data_cnt]);
> +  ++m_data_cnt;
> +  var = limb_access (TREE_TYPE (op), var, idx, false);
> +  tree r = make_ssa_name (m_limb_type);
> +  gimple *g = gimple_build_assign (r, var);
> +  insert_before (g);
> +  return r;
> +}
> +
>  /* Add a new EH edge from SRC to EH_EDGE->dest, where EH_EDGE
>     is an older EH edge, and except for virtual PHIs duplicate the
>     PHI argument from the EH_EDGE to the new EH edge.  */
> @@ -2019,6 +2102,8 @@ bitint_large_huge::handle_stmt (gimple *
>         return handle_cast (TREE_TYPE (gimple_assign_lhs (stmt)),
>                             TREE_OPERAND (gimple_assign_rhs1 (stmt), 0),
>                             idx);
> +     case BIT_FIELD_REF:
> +       return handle_bit_field_ref (gimple_assign_rhs1 (stmt), idx);
>       default:
>         break;
>       }
> --- gcc/testsuite/gcc.dg/bitint-98.c.jj       2024-03-04 19:11:46.355244244 
> +0100
> +++ gcc/testsuite/gcc.dg/bitint-98.c  2024-03-04 19:10:35.139207685 +0100
> @@ -0,0 +1,50 @@
> +/* PR middle-end/114157 */
> +/* { dg-do compile { target bitint } } */
> +/* { dg-options "-O2 -std=c23 -Wno-psabi -w" } */
> +
> +#if __BITINT_MAXWIDTH__ >= 256
> +_BitInt(256) d;
> +_BitInt(255) e;
> +
> +void
> +foo (long __attribute__((vector_size (64))) s)
> +{
> +  __builtin_memmove (&d, &s, sizeof (d));
> +}
> +
> +void
> +bar (_BitInt(512) x)
> +{
> +  long __attribute__((vector_size (64))) s;
> +  __builtin_memcpy (&s, &x, sizeof (s));
> +  __builtin_memcpy (&d, &s, sizeof (d));
> +}
> +
> +void
> +baz (long __attribute__((vector_size (64))) s)
> +{
> +  _BitInt(256) d;
> +  __builtin_memmove (&d, &s, sizeof (d));
> +  e = d;
> +}
> +
> +void
> +qux (long __attribute__((vector_size (64))) s)
> +{
> +  _BitInt(192) d;
> +  __builtin_memmove (&d, &s, sizeof (d));
> +  e = d;
> +}
> +#else
> +int i;
> +#endif
> +
> +#if __BITINT_MAXWIDTH__ >= 1024
> +_BitInt(512)
> +corge (long __attribute__((vector_size (1024))) s)
> +{
> +  _BitInt(512) d;
> +  __builtin_memcpy (&d, &s, sizeof (d));
> +  return d;
> +}
> +#endif
> --- gcc/testsuite/gcc.target/i386/avx2-pr114157.c.jj  2024-03-04 
> 19:12:46.001437331 +0100
> +++ gcc/testsuite/gcc.target/i386/avx2-pr114157.c     2024-03-04 
> 19:12:31.639631618 +0100
> @@ -0,0 +1,5 @@
> +/* PR middle-end/114157 */
> +/* { dg-do compile { target bitint } } */
> +/* { dg-options "-O2 -std=c23 -Wno-psabi -w -mavx2 -mno-avx512f" } */
> +
> +#include "../../gcc.dg/bitint-98.c"
> --- gcc/testsuite/gcc.target/i386/avx512f-pr114157.c.jj       2024-03-04 
> 19:13:01.190231847 +0100
> +++ gcc/testsuite/gcc.target/i386/avx512f-pr114157.c  2024-03-04 
> 19:13:12.018085362 +0100
> @@ -0,0 +1,5 @@
> +/* PR middle-end/114157 */
> +/* { dg-do compile { target bitint } } */
> +/* { dg-options "-O2 -std=c23 -Wno-psabi -w -mavx512f" } */
> +
> +#include "../../gcc.dg/bitint-98.c"
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to