This is what I finally settled for as suitable solution for this
PR in stage3.  There are multiple issues with the PRE implementation
and the basic insert algorithm from the paper (sic).  The implementation
already has several hacks in place to mitigate the issues in most
cases - but as usual, one case always slips through.  This plugs the
hole again by re-instantiating the failure path during insertion.
It also plugs a hole in a weird bit of code.

A proper stage1 solution would re-write the core insertion routine
and remove all failure / recursion paths from the insertion workers.
On my TODO for GCC 4.9.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2012-12-04  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/55124
        * tree-ssa-pre.c (find_or_generate_expression): Instead of
        ICEing when we are not able to generate an expression defer it
        by signalling failure.  Fix possible wrong-code issue by
        not picking random REFERENCE expressions as fallback.
        (create_component_ref_by_pieces_1): Adjust.  Add failure paths.
        (create_expression_by_pieces): Likewise.
        (insert_into_preds_of_block): When expression generation failed
        for one edge make sure to not insert a PHI node.

        * gcc.dg/torture/pr55124.c: New testcase.

Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c  (revision 194081)
--- gcc/tree-ssa-pre.c  (working copy)
*************** create_component_ref_by_pieces_1 (basic_
*** 2564,2576 ****
          fn = currop->op0;
        else
          fn = find_or_generate_expression (block, currop->op0, stmts);
        if (currop->op1)
!         sc = find_or_generate_expression (block, currop->op1, stmts);
        args = XNEWVEC (tree, ref->operands.length () - 1);
        while (*operand < ref->operands.length ())
          {
            args[nargs] = create_component_ref_by_pieces_1 (block, ref,
                                                            operand, stmts);
            nargs++;
          }
        folded = build_call_array (currop->type,
--- 2564,2584 ----
          fn = currop->op0;
        else
          fn = find_or_generate_expression (block, currop->op0, stmts);
+       if (!fn)
+         return NULL_TREE;
        if (currop->op1)
!         {
!           sc = find_or_generate_expression (block, currop->op1, stmts);
!           if (!sc)
!             return NULL_TREE;
!         }
        args = XNEWVEC (tree, ref->operands.length () - 1);
        while (*operand < ref->operands.length ())
          {
            args[nargs] = create_component_ref_by_pieces_1 (block, ref,
                                                            operand, stmts);
+           if (!args[nargs])
+             return NULL_TREE;
            nargs++;
          }
        folded = build_call_array (currop->type,
*************** create_component_ref_by_pieces_1 (basic_
*** 2587,2592 ****
--- 2595,2602 ----
        {
        tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
                                                        stmts);
+       if (!baseop)
+         return NULL_TREE;
        tree offset = currop->op0;
        if (TREE_CODE (baseop) == ADDR_EXPR
            && handled_component_p (TREE_OPERAND (baseop, 0)))
*************** create_component_ref_by_pieces_1 (basic_
*** 2610,2619 ****
        vn_reference_op_t nextop = &ref->operands[++*operand];
        tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
                                                        stmts);
        if (currop->op0)
!         genop0 = find_or_generate_expression (block, currop->op0, stmts);
        if (nextop->op0)
!         genop1 = find_or_generate_expression (block, nextop->op0, stmts);
        return build5 (TARGET_MEM_REF, currop->type,
                       baseop, currop->op2, genop0, currop->op1, genop1);
        }
--- 2620,2639 ----
        vn_reference_op_t nextop = &ref->operands[++*operand];
        tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
                                                        stmts);
+       if (!baseop)
+         return NULL_TREE;
        if (currop->op0)
!         {
!           genop0 = find_or_generate_expression (block, currop->op0, stmts);
!           if (!genop0)
!             return NULL_TREE;
!         }
        if (nextop->op0)
!         {
!           genop1 = find_or_generate_expression (block, nextop->op0, stmts);
!           if (!genop1)
!             return NULL_TREE;
!         }
        return build5 (TARGET_MEM_REF, currop->type,
                       baseop, currop->op2, genop0, currop->op1, genop1);
        }
*************** create_component_ref_by_pieces_1 (basic_
*** 2629,2636 ****
      case IMAGPART_EXPR:
      case VIEW_CONVERT_EXPR:
        {
!       tree genop0 = create_component_ref_by_pieces_1 (block, ref,
!                                                       operand, stmts);
        return fold_build1 (currop->opcode, currop->type, genop0);
        }
  
--- 2649,2658 ----
      case IMAGPART_EXPR:
      case VIEW_CONVERT_EXPR:
        {
!       tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
!                                                       stmts);
!       if (!genop0)
!         return NULL_TREE;
        return fold_build1 (currop->opcode, currop->type, genop0);
        }
  
*************** create_component_ref_by_pieces_1 (basic_
*** 2638,2644 ****
--- 2660,2670 ----
        {
        tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
                                                        stmts);
+       if (!genop0)
+         return NULL_TREE;
        tree genop1 = find_or_generate_expression (block, currop->op0, stmts);
+       if (!genop1)
+         return NULL_TREE;
        return fold_build2 (currop->opcode, currop->type, genop0, genop1);
        }
  
*************** create_component_ref_by_pieces_1 (basic_
*** 2646,2651 ****
--- 2672,2679 ----
        {
        tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
                                                        stmts);
+       if (!genop0)
+         return NULL_TREE;
        tree op1 = currop->op0;
        tree op2 = currop->op1;
        return fold_build3 (BIT_FIELD_REF, currop->type, genop0, op1, op2);
*************** create_component_ref_by_pieces_1 (basic_
*** 2661,2668 ****
        tree genop1 = currop->op0;
        tree genop2 = currop->op1;
        tree genop3 = currop->op2;
!       genop0 = create_component_ref_by_pieces_1 (block, ref, operand, stmts);
        genop1 = find_or_generate_expression (block, genop1, stmts);
        if (genop2)
          {
            tree domain_type = TYPE_DOMAIN (TREE_TYPE (genop0));
--- 2689,2701 ----
        tree genop1 = currop->op0;
        tree genop2 = currop->op1;
        tree genop3 = currop->op2;
!       genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
!                                                  stmts);
!       if (!genop0)
!         return NULL_TREE;
        genop1 = find_or_generate_expression (block, genop1, stmts);
+       if (!genop1)
+         return NULL_TREE;
        if (genop2)
          {
            tree domain_type = TYPE_DOMAIN (TREE_TYPE (genop0));
*************** create_component_ref_by_pieces_1 (basic_
*** 2672,2678 ****
                    || integer_zerop (TYPE_MIN_VALUE (domain_type))))
              genop2 = NULL_TREE;
            else
!             genop2 = find_or_generate_expression (block, genop2, stmts);
          }
        if (genop3)
          {
--- 2705,2715 ----
                    || integer_zerop (TYPE_MIN_VALUE (domain_type))))
              genop2 = NULL_TREE;
            else
!             {
!               genop2 = find_or_generate_expression (block, genop2, stmts);
!               if (!genop2)
!                 return NULL_TREE;
!             }
          }
        if (genop3)
          {
*************** create_component_ref_by_pieces_1 (basic_
*** 2688,2693 ****
--- 2725,2732 ----
                genop3 = size_binop (EXACT_DIV_EXPR, genop3,
                                     size_int (TYPE_ALIGN_UNIT (elmt_type)));
                genop3 = find_or_generate_expression (block, genop3, stmts);
+               if (!genop3)
+                 return NULL_TREE;
              }
          }
        return build4 (currop->opcode, currop->type, genop0, genop1,
*************** create_component_ref_by_pieces_1 (basic_
*** 2699,2708 ****
        tree op1;
        tree genop2 = currop->op1;
        op0 = create_component_ref_by_pieces_1 (block, ref, operand, stmts);
        /* op1 should be a FIELD_DECL, which are represented by themselves.  */
        op1 = currop->op0;
        if (genop2)
!         genop2 = find_or_generate_expression (block, genop2, stmts);
        return fold_build3 (COMPONENT_REF, TREE_TYPE (op1), op0, op1, genop2);
        }
  
--- 2738,2753 ----
        tree op1;
        tree genop2 = currop->op1;
        op0 = create_component_ref_by_pieces_1 (block, ref, operand, stmts);
+       if (!op0)
+         return NULL_TREE;
        /* op1 should be a FIELD_DECL, which are represented by themselves.  */
        op1 = currop->op0;
        if (genop2)
!         {
!           genop2 = find_or_generate_expression (block, genop2, stmts);
!           if (!genop2)
!             return NULL_TREE;
!         }
        return fold_build3 (COMPONENT_REF, TREE_TYPE (op1), op0, op1, genop2);
        }
  
*************** create_component_ref_by_pieces (basic_bl
*** 2749,2766 ****
    return create_component_ref_by_pieces_1 (block, ref, &op, stmts);
  }
  
! /* Find a leader for an expression, or generate one using
!    create_expression_by_pieces if it's ANTIC but
!    complex.
     BLOCK is the basic_block we are looking for leaders in.
     OP is the tree expression to find a leader for or generate.
!    STMTS is the statement list to put the inserted expressions on.
!    Returns the SSA_NAME of the LHS of the generated expression or the
!    leader.
!    DOMSTMT if non-NULL is a statement that should be dominated by
!    all uses in the generated expression.  If DOMSTMT is non-NULL this
!    routine can fail and return NULL_TREE.  Otherwise it will assert
!    on failure.  */
  
  static tree
  find_or_generate_expression (basic_block block, tree op, gimple_seq *stmts)
--- 2794,2804 ----
    return create_component_ref_by_pieces_1 (block, ref, &op, stmts);
  }
  
! /* Find a simple leader for an expression, or generate one using
!    create_expression_by_pieces from a NARY expression for the value.
     BLOCK is the basic_block we are looking for leaders in.
     OP is the tree expression to find a leader for or generate.
!    Returns the leader or NULL_TREE on failure.  */
  
  static tree
  find_or_generate_expression (basic_block block, tree op, gimple_seq *stmts)
*************** find_or_generate_expression (basic_block
*** 2774,2794 ****
        return PRE_EXPR_NAME (leader);
        else if (leader->kind == CONSTANT)
        return PRE_EXPR_CONSTANT (leader);
      }
  
!   /* It must be a complex expression, so generate it recursively.  */
    bitmap exprset = value_expressions[lookfor];
    bitmap_iterator bi;
    unsigned int i;
    EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
      {
        pre_expr temp = expression_for_id (i);
!       if (temp->kind != NAME)
        return create_expression_by_pieces (block, temp, stmts,
                                            get_expr_type (expr));
      }
  
!   gcc_unreachable ();
  }
  
  #define NECESSARY GF_PLF_1
--- 2812,2841 ----
        return PRE_EXPR_NAME (leader);
        else if (leader->kind == CONSTANT)
        return PRE_EXPR_CONSTANT (leader);
+ 
+       /* Defer.  */
+       return NULL_TREE;
      }
  
!   /* It must be a complex expression, so generate it recursively.  Note
!      that this is only necessary to handle gcc.dg/tree-ssa/ssa-pre28.c
!      where the insert algorithm fails to insert a required expression.  */
    bitmap exprset = value_expressions[lookfor];
    bitmap_iterator bi;
    unsigned int i;
    EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
      {
        pre_expr temp = expression_for_id (i);
!       /* We cannot insert random REFERENCE expressions at arbitrary
!        places.  We can insert NARYs which eventually re-materializes
!        its operand values.  */
!       if (temp->kind == NARY)
        return create_expression_by_pieces (block, temp, stmts,
                                            get_expr_type (expr));
      }
  
!   /* Defer.  */
!   return NULL_TREE;
  }
  
  #define NECESSARY GF_PLF_1
*************** find_or_generate_expression (basic_block
*** 2801,2815 ****
  
     This function will die if we hit some value that shouldn't be
     ANTIC but is (IE there is no leader for it, or its components).
     This function may also generate expressions that are themselves
     partially or fully redundant.  Those that are will be either made
     fully redundant during the next iteration of insert (for partially
     redundant ones), or eliminated by eliminate (for fully redundant
!    ones).
! 
!    If DOMSTMT is non-NULL then we make sure that all uses in the
!    expressions dominate that statement.  In this case the function
!    can return NULL_TREE to signal failure.  */
  
  static tree
  create_expression_by_pieces (basic_block block, pre_expr expr,
--- 2848,2860 ----
  
     This function will die if we hit some value that shouldn't be
     ANTIC but is (IE there is no leader for it, or its components).
+    The function returns NULL_TREE in case a different antic expression
+    has to be inserted first.
     This function may also generate expressions that are themselves
     partially or fully redundant.  Those that are will be either made
     fully redundant during the next iteration of insert (for partially
     redundant ones), or eliminated by eliminate (for fully redundant
!    ones).  */
  
  static tree
  create_expression_by_pieces (basic_block block, pre_expr expr,
*************** create_expression_by_pieces (basic_block
*** 2838,2843 ****
--- 2883,2890 ----
        {
        vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
        folded = create_component_ref_by_pieces (block, ref, stmts);
+       if (!folded)
+         return NULL_TREE;
        }
        break;
      case NARY:
*************** create_expression_by_pieces (basic_block
*** 2848,2853 ****
--- 2895,2902 ----
        for (i = 0; i < nary->length; ++i)
          {
            genop[i] = find_or_generate_expression (block, nary->op[i], stmts);
+           if (!genop[i])
+             return NULL_TREE;
            /* Ensure genop[] is properly typed for POINTER_PLUS_EXPR.  It
               may have conversions stripped.  */
            if (nary->opcode == POINTER_PLUS_EXPR)
*************** insert_into_preds_of_block (basic_block
*** 3085,3090 ****
--- 3134,3146 ----
                                                   &stmts, type);
          gcc_assert (!(pred->flags & EDGE_ABNORMAL));
          gsi_insert_seq_on_edge (pred, stmts);
+         if (!builtexpr)
+           {
+             /* We cannot insert a PHI node if we failed to insert
+                on one edge.  */
+             nophi = true;
+             continue;
+           }
          avail[pred->dest_idx] = get_or_alloc_expr_for_name (builtexpr);
          insertions = true;
        }
Index: gcc/testsuite/gcc.dg/torture/pr55124.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr55124.c      (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr55124.c      (working copy)
***************
*** 0 ****
--- 1,20 ----
+ /* { dg-do compile } */
+ 
+ int a, b;
+ long c;
+ 
+ void f2(void)
+ {
+   unsigned long k = 1;
+ 
+   foo(b ? k = 0 : 0);
+ 
+   b = ((c = b) ? (k ? : (c = 0)) : a) * c;
+ }
+ 
+ void f1(void)
+ {
+   f2();
+ 
+   a = b | c;
+ }

Reply via email to