https://gcc.gnu.org/g:f33d2e6b532304d487193667e6b5d8f8d7df2bf4

commit r15-9426-gf33d2e6b532304d487193667e6b5d8f8d7df2bf4
Author: Martin Jambor <mjam...@suse.cz>
Date:   Mon Apr 14 14:21:14 2025 +0200

    ipa: Record and stream result types of arithemetic jump functions
    
    In order to replace the use of somewhat unweildy
    expr_type_first_operand_type_p we need to record and stream the types
    of results of operations recorded in arithmetic jump functions.  This
    is necessary so that we can then simulate them at the IPA stage with
    the corresponding precision and signedness.  This patch does the
    recorsing and streaming, the following one adds the use of the date.
    
    Per Honza's request this version also checks that we do not put VLA
    types into the global LTO stream, even though I was not able to
    actually craft a test-case that would do that without them.
    
    gcc/ChangeLog:
    
    2025-04-11  Martin Jambor  <mjam...@suse.cz>
    
            PR ipa/118097
            PR ipa/118785
            PR ipa/119318
            * lto-streamer.h (lto_variably_modified_type_p): Declare.
            * ipa-prop.h (ipa_pass_through_data): New field op_type.
            (ipa_get_jf_pass_through_op_type): New function.
            * ipa-prop.cc: Include lto-streamer.h.
            (ipa_dump_jump_function): Dump also pass-through
            operation types, if any.  Dump pass-through operands only if not 
NULL.
            (ipa_set_jf_simple_pass_through): Set op_type accordingly.
            (compute_complex_assign_jump_func): Set op_type of arithmetic
            pass-through jump_functions.
            (analyze_agg_content_value): Update lhs when walking assighment
            copies.  Set op_type of aggregate arithmetic pass-through
            jump_functions.
            (update_jump_functions_after_inlining): Also transfer the operation
            type from the source arithmentic pass-through jump function to the
            destination jump function.
            (ipa_write_jump_function): Stream also the op_type when necessary.
            (ipa_read_jump_function): Likewise.
            (ipa_agg_pass_through_jf_equivalent_p): Also compare operation 
types.
            * lto-streamer-out.cc (lto_variably_modified_type_p): Make public.

Diff:
---
 gcc/ipa-prop.cc         | 76 ++++++++++++++++++++++++++++++++++++++++---------
 gcc/ipa-prop.h          | 15 ++++++++++
 gcc/lto-streamer-out.cc |  2 +-
 gcc/lto-streamer.h      |  1 +
 4 files changed, 80 insertions(+), 14 deletions(-)

diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index a120f942dc25..49d68ab044b7 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-range.h"
 #include "value-range-storage.h"
 #include "vr-values.h"
+#include "lto-streamer.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
@@ -454,7 +455,11 @@ ipa_dump_jump_function (FILE *f, ipa_jump_func *jump_func,
       if (jump_func->value.pass_through.operation != NOP_EXPR)
        {
          fprintf (f, " ");
-         print_generic_expr (f, jump_func->value.pass_through.operand);
+         if (jump_func->value.pass_through.operand)
+           print_generic_expr (f, jump_func->value.pass_through.operand);
+         fprintf (f, " (in type ");
+         print_generic_expr (f, jump_func->value.pass_through.op_type);
+         fprintf (f, ")");
        }
       if (jump_func->value.pass_through.agg_preserved)
        fprintf (f, ", agg_preserved");
@@ -510,7 +515,11 @@ ipa_dump_jump_function (FILE *f, ipa_jump_func *jump_func,
              if (item->value.pass_through.operation != NOP_EXPR)
                {
                  fprintf (f, " ");
-                 print_generic_expr (f, item->value.pass_through.operand);
+                 if (item->value.pass_through.operand)
+                   print_generic_expr (f, item->value.pass_through.operand);
+                 fprintf (f, " (in type ");
+                 print_generic_expr (f, jump_func->value.pass_through.op_type);
+                 fprintf (f, ")");
                }
            }
          else if (item->jftype == IPA_JF_CONST)
@@ -682,6 +691,7 @@ ipa_set_jf_simple_pass_through (struct ipa_jump_func 
*jfunc, int formal_id,
 {
   jfunc->type = IPA_JF_PASS_THROUGH;
   jfunc->value.pass_through.operand = NULL_TREE;
+  jfunc->value.pass_through.op_type = NULL_TREE;
   jfunc->value.pass_through.formal_id = formal_id;
   jfunc->value.pass_through.operation = NOP_EXPR;
   jfunc->value.pass_through.agg_preserved = agg_preserved;
@@ -692,10 +702,11 @@ ipa_set_jf_simple_pass_through (struct ipa_jump_func 
*jfunc, int formal_id,
 
 static void
 ipa_set_jf_unary_pass_through (struct ipa_jump_func *jfunc, int formal_id,
-                              enum tree_code operation)
+                              enum tree_code operation, tree op_type)
 {
   jfunc->type = IPA_JF_PASS_THROUGH;
   jfunc->value.pass_through.operand = NULL_TREE;
+  jfunc->value.pass_through.op_type = op_type;
   jfunc->value.pass_through.formal_id = formal_id;
   jfunc->value.pass_through.operation = operation;
   jfunc->value.pass_through.agg_preserved = false;
@@ -705,10 +716,12 @@ ipa_set_jf_unary_pass_through (struct ipa_jump_func 
*jfunc, int formal_id,
 
 static void
 ipa_set_jf_arith_pass_through (struct ipa_jump_func *jfunc, int formal_id,
-                              tree operand, enum tree_code operation)
+                              tree operand, enum tree_code operation,
+                              tree op_type)
 {
   jfunc->type = IPA_JF_PASS_THROUGH;
   jfunc->value.pass_through.operand = unshare_expr_without_location (operand);
+  jfunc->value.pass_through.op_type = op_type;
   jfunc->value.pass_through.formal_id = formal_id;
   jfunc->value.pass_through.operation = operation;
   jfunc->value.pass_through.agg_preserved = false;
@@ -1513,6 +1526,9 @@ compute_complex_assign_jump_func (struct 
ipa_func_body_info *fbi,
 
   if (index >= 0)
     {
+      if (lto_variably_modified_type_p (TREE_TYPE (name)))
+       return;
+
       switch (gimple_assign_rhs_class (stmt))
        {
        case GIMPLE_BINARY_RHS:
@@ -1526,7 +1542,8 @@ compute_complex_assign_jump_func (struct 
ipa_func_body_info *fbi,
              return;
 
            ipa_set_jf_arith_pass_through (jfunc, index, op2,
-                                          gimple_assign_rhs_code (stmt));
+                                          gimple_assign_rhs_code (stmt),
+                                          TREE_TYPE (name));
            break;
          }
        case GIMPLE_SINGLE_RHS:
@@ -1539,7 +1556,8 @@ compute_complex_assign_jump_func (struct 
ipa_func_body_info *fbi,
        case GIMPLE_UNARY_RHS:
          if (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)))
            ipa_set_jf_unary_pass_through (jfunc, index,
-                                          gimple_assign_rhs_code (stmt));
+                                          gimple_assign_rhs_code (stmt),
+                                          TREE_TYPE (name));
        default:;
        }
       return;
@@ -1912,6 +1930,7 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi,
       if (!is_gimple_assign (stmt))
        break;
 
+      lhs = gimple_assign_lhs (stmt);
       rhs1 = gimple_assign_rhs1 (stmt);
     }
 
@@ -1931,7 +1950,8 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi,
         PASS-THROUGH jump function with ASSERT_EXPR operation whith operand 1
         (the constant from the PHI node).  */
 
-      if (gimple_phi_num_args (phi) != 2)
+      if (gimple_phi_num_args (phi) != 2
+         || lto_variably_modified_type_p (TREE_TYPE (lhs)))
        return;
       tree arg0 = gimple_phi_arg_def (phi, 0);
       tree arg1 = gimple_phi_arg_def (phi, 1);
@@ -1956,6 +1976,7 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi,
 
       code = ASSERT_EXPR;
       agg_value->pass_through.operand = operand;
+      agg_value->pass_through.op_type = TREE_TYPE (lhs);
     }
   else if (is_gimple_assign (stmt))
     {
@@ -1980,10 +2001,12 @@ analyze_agg_content_value (struct ipa_func_body_info 
*fbi,
             with one operand, here we only allow tc_unary operation to avoid
             possible problem.  Then we can use (opclass == tc_unary) or not to
             distinguish unary and binary.  */
-         if (TREE_CODE_CLASS (code) != tcc_unary || CONVERT_EXPR_CODE_P (code))
+         if (TREE_CODE_CLASS (code) != tcc_unary || CONVERT_EXPR_CODE_P (code)
+             || lto_variably_modified_type_p (TREE_TYPE (lhs)))
            return;
 
          rhs1 = get_ssa_def_if_simple_copy (rhs1, &stmt);
+         agg_value->pass_through.op_type = TREE_TYPE (lhs);
          break;
 
        case GIMPLE_BINARY_RHS:
@@ -1992,12 +2015,16 @@ analyze_agg_content_value (struct ipa_func_body_info 
*fbi,
            gimple *rhs2_stmt = stmt;
            tree rhs2 = gimple_assign_rhs2 (stmt);
 
+           if (lto_variably_modified_type_p (TREE_TYPE (lhs)))
+             return;
+
            rhs1 = get_ssa_def_if_simple_copy (rhs1, &rhs1_stmt);
            rhs2 = get_ssa_def_if_simple_copy (rhs2, &rhs2_stmt);
 
            if (is_gimple_ip_invariant (rhs2))
              {
                agg_value->pass_through.operand = rhs2;
+               agg_value->pass_through.op_type = TREE_TYPE (lhs);
                stmt = rhs1_stmt;
              }
            else if (is_gimple_ip_invariant (rhs1))
@@ -2008,6 +2035,7 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi,
                  return;
 
                agg_value->pass_through.operand = rhs1;
+               agg_value->pass_through.op_type = TREE_TYPE (lhs);
                stmt = rhs2_stmt;
                rhs1 = rhs2;
              }
@@ -3520,12 +3548,17 @@ update_jump_functions_after_inlining (struct 
cgraph_edge *cs,
                        ipa_set_jf_simple_pass_through (dst, formal_id, agg_p);
                      }
                    else if (TREE_CODE_CLASS (operation) == tcc_unary)
-                     ipa_set_jf_unary_pass_through (dst, formal_id, operation);
+                     {
+                       tree op_t = ipa_get_jf_pass_through_op_type (src);
+                       ipa_set_jf_unary_pass_through (dst, formal_id, 
operation,
+                                                      op_t);
+                     }
                    else
                      {
                        tree operand = ipa_get_jf_pass_through_operand (src);
+                       tree op_t = ipa_get_jf_pass_through_op_type (src);
                        ipa_set_jf_arith_pass_through (dst, formal_id, operand,
-                                                      operation);
+                                                      operation, op_t);
                      }
                    break;
                  }
@@ -4935,9 +4968,13 @@ ipa_write_jump_function (struct output_block *ob,
        }
       else if (TREE_CODE_CLASS (jump_func->value.pass_through.operation)
               == tcc_unary)
-       streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
+       {
+         stream_write_tree (ob, jump_func->value.pass_through.op_type, true);
+         streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
+       }
       else
        {
+         stream_write_tree (ob, jump_func->value.pass_through.op_type, true);
          stream_write_tree (ob, jump_func->value.pass_through.operand, true);
          streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
        }
@@ -4979,6 +5016,8 @@ ipa_write_jump_function (struct output_block *ob,
        case IPA_JF_LOAD_AGG:
          streamer_write_uhwi (ob, item->value.pass_through.operation);
          streamer_write_uhwi (ob, item->value.pass_through.formal_id);
+         if (item->value.pass_through.operation != NOP_EXPR)
+           stream_write_tree (ob, item->value.pass_through.op_type, true);
          if (TREE_CODE_CLASS (item->value.pass_through.operation)
                                                        != tcc_unary)
            stream_write_tree (ob, item->value.pass_through.operand, true);
@@ -5047,15 +5086,18 @@ ipa_read_jump_function (class lto_input_block *ib,
        }
       else if (TREE_CODE_CLASS (operation) == tcc_unary)
        {
+         tree op_type = stream_read_tree (ib, data_in);
          int formal_id =  streamer_read_uhwi (ib);
-         ipa_set_jf_unary_pass_through (jump_func, formal_id, operation);
+         ipa_set_jf_unary_pass_through (jump_func, formal_id, operation,
+                                        op_type);
        }
       else
        {
+         tree op_type = stream_read_tree (ib, data_in);
          tree operand = stream_read_tree (ib, data_in);
          int formal_id =  streamer_read_uhwi (ib);
          ipa_set_jf_arith_pass_through (jump_func, formal_id, operand,
-                                        operation);
+                                        operation, op_type);
        }
       break;
     case IPA_JF_ANCESTOR:
@@ -5103,6 +5145,10 @@ ipa_read_jump_function (class lto_input_block *ib,
          operation = (enum tree_code) streamer_read_uhwi (ib);
          item.value.pass_through.operation = operation;
          item.value.pass_through.formal_id = streamer_read_uhwi (ib);
+         if (operation != NOP_EXPR)
+           item.value.pass_through.op_type = stream_read_tree (ib, data_in);
+         else
+           item.value.pass_through.op_type = NULL_TREE;
          if (TREE_CODE_CLASS (operation) == tcc_unary)
            item.value.pass_through.operand = NULL_TREE;
          else
@@ -6224,6 +6270,10 @@ ipa_agg_pass_through_jf_equivalent_p 
(ipa_pass_through_data *ipt1,
       || ipt1->formal_id != ipt2->formal_id
       || (!agg_jf && (ipt1->agg_preserved != ipt2->agg_preserved)))
     return false;
+  if (ipt1->operation != NOP_EXPR
+      && (TYPE_MAIN_VARIANT (ipt1->op_type)
+         != TYPE_MAIN_VARIANT (ipt2->op_type)))
+    return false;
   if (((ipt1->operand != NULL_TREE) != (ipt2->operand != NULL_TREE))
       || (ipt1->operand
          && !values_equal_for_ipcp_p (ipt1->operand, ipt2->operand)))
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 7735b573f035..3bd442fff395 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -96,6 +96,9 @@ struct GTY(()) ipa_pass_through_data
   /* If an operation is to be performed on the original parameter, this is the
      second (constant) operand.  */
   tree operand;
+  /* The result type of the operation.  In case of no operation (represented by
+     NOP_EXPR) it should be NULL_TREE.  */
+  tree op_type;
   /* Number of the caller's formal parameter being passed.  */
   int formal_id;
   /* Operation that is performed on the argument before it is passed on.
@@ -387,6 +390,18 @@ ipa_get_jf_pass_through_operand (struct ipa_jump_func 
*jfunc)
   return jfunc->value.pass_through.operand;
 }
 
+/* Return the type of the operation in a non-NOP pass through jmp function
+   JFUNC.  */
+
+inline tree
+ipa_get_jf_pass_through_op_type (struct ipa_jump_func *jfunc)
+{
+  gcc_checking_assert (jfunc->type == IPA_JF_PASS_THROUGH
+                      && jfunc->value.pass_through.operation != NOP_EXPR);
+
+  return jfunc->value.pass_through.op_type;
+}
+
 /* Return the number of the caller's formal parameter that a pass through jump
    function JFUNC refers to.  */
 
diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc
index d5b6ee74d573..a055d12d6bed 100644
--- a/gcc/lto-streamer-out.cc
+++ b/gcc/lto-streamer-out.cc
@@ -130,7 +130,7 @@ destroy_output_block (struct output_block *ob)
 /* Wrapper around variably_modified_type_p avoiding type modification
    during WPA streaming.  */
 
-static bool
+bool
 lto_variably_modified_type_p (tree type)
 {
   return (in_lto_p
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index ff33bf01d88c..4b7209e3d82d 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -906,6 +906,7 @@ void lto_output_decl_state_streams (struct output_block *,
 void lto_output_decl_state_refs (struct output_block *,
                                 struct lto_output_stream *,
                                 struct lto_out_decl_state *);
+bool lto_variably_modified_type_p (tree);
 void lto_output_location (struct output_block *, struct bitpack_d *,
                          location_t);
 void lto_output_location_and_block (struct output_block *, struct bitpack_d *,

Reply via email to