OSDN Git Service

* gcc.target/i386/pr34256.c: Update number of mov insns
[pf3gnuchains/gcc-fork.git] / gcc / tree-gimple.c
index cabe546..d1e47f6 100644 (file)
@@ -1,5 +1,6 @@
 /* Functions to analyze and validate GIMPLE trees.
 /* Functions to analyze and validate GIMPLE trees.
-   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
    Rewritten by Jason Merrill <jason@redhat.com>
 
    Contributed by Diego Novillo <dnovillo@redhat.com>
    Rewritten by Jason Merrill <jason@redhat.com>
 
@@ -7,7 +8,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -16,9 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
@@ -33,162 +33,7 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h"
 #include "bitmap.h"
 
 #include "expr.h"
 #include "bitmap.h"
 
-/* GCC GIMPLE structure
-
-   Inspired by the SIMPLE C grammar at
-
-       http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html
-
-   function    : FUNCTION_DECL
-                       DECL_SAVED_TREE -> compound-stmt
-
-   compound-stmt: STATEMENT_LIST
-                       members -> stmt
-
-   stmt                : block
-               | if-stmt
-               | switch-stmt
-               | goto-stmt
-               | return-stmt
-               | resx-stmt
-               | label-stmt
-               | try-stmt
-               | modify-stmt
-               | call-stmt
-
-   block       : BIND_EXPR
-                       BIND_EXPR_VARS -> chain of DECLs
-                       BIND_EXPR_BLOCK -> BLOCK
-                       BIND_EXPR_BODY -> compound-stmt
-
-   if-stmt     : COND_EXPR
-                       op0 -> condition
-                       op1 -> compound-stmt
-                       op2 -> compound-stmt
-
-   switch-stmt : SWITCH_EXPR
-                       op0 -> val
-                       op1 -> NULL
-                       op2 -> TREE_VEC of CASE_LABEL_EXPRs
-                           The CASE_LABEL_EXPRs are sorted by CASE_LOW,
-                           and default is last.
-
-   goto-stmt   : GOTO_EXPR
-                       op0 -> LABEL_DECL | val
-
-   return-stmt : RETURN_EXPR
-                       op0 -> return-value
-
-   return-value        : NULL
-               | RESULT_DECL
-               | MODIFY_EXPR
-                       op0 -> RESULT_DECL
-                       op1 -> lhs
-
-   resx-stmt   : RESX_EXPR
-
-   label-stmt  : LABEL_EXPR
-                       op0 -> LABEL_DECL
-
-   try-stmt    : TRY_CATCH_EXPR
-                       op0 -> compound-stmt
-                       op1 -> handler
-               | TRY_FINALLY_EXPR
-                       op0 -> compound-stmt
-                       op1 -> compound-stmt
-
-   handler     : catch-seq
-               | EH_FILTER_EXPR
-               | compound-stmt
-
-   catch-seq   : STATEMENT_LIST
-                       members -> CATCH_EXPR
-
-   modify-stmt : MODIFY_EXPR
-                       op0 -> lhs
-                       op1 -> rhs
-
-   call-stmt   : CALL_EXPR
-                       op0 -> val | OBJ_TYPE_REF
-                       op1 -> call-arg-list
-
-   call-arg-list: TREE_LIST
-                       members -> lhs
-
-   addr-expr-arg: ID
-               | compref
-
-   addressable : addr-expr-arg
-               | indirectref
-
-   with-size-arg: addressable
-               | call-stmt
-
-   indirectref : INDIRECT_REF
-                       op0 -> val
-
-   lhs         : addressable
-               | bitfieldref
-               | WITH_SIZE_EXPR
-                       op0 -> with-size-arg
-                       op1 -> val
-
-   min-lval    : ID
-               | indirectref
-
-   bitfieldref : BIT_FIELD_REF
-                       op0 -> inner-compref
-                       op1 -> CONST
-                       op2 -> var
-
-   compref     : inner-compref
-               | REALPART_EXPR
-                       op0 -> inner-compref
-               | IMAGPART_EXPR
-                       op0 -> inner-compref
-
-   inner-compref: min-lval
-               | COMPONENT_REF
-                       op0 -> inner-compref
-                       op1 -> FIELD_DECL
-                       op2 -> val
-               | ARRAY_REF
-                       op0 -> inner-compref
-                       op1 -> val
-                       op2 -> val
-                       op3 -> val
-               | ARRAY_RANGE_REF
-                       op0 -> inner-compref
-                       op1 -> val
-                       op2 -> val
-                       op3 -> val
-               | VIEW_CONVERT_EXPR
-                       op0 -> inner-compref
-
-   condition   : val
-               | RELOP
-                       op0 -> val
-                       op1 -> val
-
-   val         : ID
-               | CONST
-
-   rhs         : lhs
-               | CONST
-               | call-stmt
-               | ADDR_EXPR
-                       op0 -> addr-expr-arg
-               | UNOP
-                       op0 -> val
-               | BINOP
-                       op0 -> val
-                       op1 -> val
-               | RELOP
-                       op0 -> val
-                       op1 -> val
-*/
-
-static inline bool is_gimple_id (tree);
+/* For the definitive definition of GIMPLE, see doc/tree-ssa.texi.  */
 
 /* Validation of GIMPLE expressions.  */
 
 
 /* Validation of GIMPLE expressions.  */
 
@@ -201,9 +46,9 @@ is_gimple_formal_tmp_rhs (tree t)
 
   switch (TREE_CODE_CLASS (code))
     {
 
   switch (TREE_CODE_CLASS (code))
     {
-    case '1':
-    case '2':
-    case '<':
+    case tcc_unary:
+    case tcc_binary:
+    case tcc_comparison:
       return true;
 
     default:
       return true;
 
     default:
@@ -216,16 +61,19 @@ is_gimple_formal_tmp_rhs (tree t)
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
     case TRUTH_XOR_EXPR:
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
     case TRUTH_XOR_EXPR:
+    case COND_EXPR:
     case ADDR_EXPR:
     case CALL_EXPR:
     case CONSTRUCTOR:
     case COMPLEX_EXPR:
     case INTEGER_CST:
     case REAL_CST:
     case ADDR_EXPR:
     case CALL_EXPR:
     case CONSTRUCTOR:
     case COMPLEX_EXPR:
     case INTEGER_CST:
     case REAL_CST:
+    case FIXED_CST:
     case STRING_CST:
     case COMPLEX_CST:
     case VECTOR_CST:
     case OBJ_TYPE_REF:
     case STRING_CST:
     case COMPLEX_CST:
     case VECTOR_CST:
     case OBJ_TYPE_REF:
+    case ASSERT_EXPR:
       return true;
 
     default:
       return true;
 
     default:
@@ -241,13 +89,13 @@ is_gimple_formal_tmp_rhs (tree t)
 bool
 is_gimple_reg_rhs (tree t)
 {
 bool
 is_gimple_reg_rhs (tree t)
 {
-  /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto
+  /* If the RHS of the GIMPLE_MODIFY_STMT may throw or make a nonlocal goto
      and the LHS is a user variable, then we need to introduce a formal
      temporary.  This way the optimizers can determine that the user
      variable is only modified if evaluation of the RHS does not throw.
 
      Don't force a temp of a non-renamable type; the copy could be
      and the LHS is a user variable, then we need to introduce a formal
      temporary.  This way the optimizers can determine that the user
      variable is only modified if evaluation of the RHS does not throw.
 
      Don't force a temp of a non-renamable type; the copy could be
-     arbitrarily expensive.  Instead we will generate a V_MAY_DEF for
+     arbitrarily expensive.  Instead we will generate a VDEF for
      the assignment.  */
 
   if (is_gimple_reg_type (TREE_TYPE (t))
      the assignment.  */
 
   if (is_gimple_reg_type (TREE_TYPE (t))
@@ -264,9 +112,14 @@ is_gimple_reg_rhs (tree t)
 bool
 is_gimple_mem_rhs (tree t)
 {
 bool
 is_gimple_mem_rhs (tree t)
 {
-  /* If we're dealing with a renamable type, either source or dest
-     must be a renamed variable.  */
-  if (is_gimple_reg_type (TREE_TYPE (t)))
+  /* If we're dealing with a renamable type, either source or dest must be
+     a renamed variable.  Also force a temporary if the type doesn't need
+     to be stored in memory, since it's cheap and prevents erroneous
+     tailcalls (PR 17526).  */
+  if (is_gimple_reg_type (TREE_TYPE (t))
+      || (TYPE_MODE (TREE_TYPE (t)) != BLKmode
+         && (TREE_CODE (t) != CALL_EXPR
+              || ! aggregate_value_p (t, t))))
     return is_gimple_val (t);
   else
     return is_gimple_formal_tmp_rhs (t);
     return is_gimple_val (t);
   else
     return is_gimple_formal_tmp_rhs (t);
@@ -285,16 +138,6 @@ rhs_predicate_for (tree lhs)
     return is_gimple_mem_rhs;
 }
 
     return is_gimple_mem_rhs;
 }
 
-/* Returns true if T is a valid CONSTRUCTOR component in GIMPLE, either
-   a val or another CONSTRUCTOR.  */
-
-bool
-is_gimple_constructor_elt (tree t)
-{
-  return (is_gimple_val (t)
-         || TREE_CODE (t) == CONSTRUCTOR);
-}
-
 /*  Return true if T is a valid LHS for a GIMPLE assignment expression.  */
 
 bool
 /*  Return true if T is a valid LHS for a GIMPLE assignment expression.  */
 
 bool
@@ -312,8 +155,7 @@ is_gimple_lvalue (tree t)
 bool
 is_gimple_condexpr (tree t)
 {
 bool
 is_gimple_condexpr (tree t)
 {
-  return (is_gimple_val (t)
-         || TREE_CODE_CLASS (TREE_CODE (t)) == '<');
+  return (is_gimple_val (t) || COMPARISON_CLASS_P (t));
 }
 
 /*  Return true if T is something whose address can be taken.  */
 }
 
 /*  Return true if T is something whose address can be taken.  */
@@ -322,16 +164,14 @@ bool
 is_gimple_addressable (tree t)
 {
   return (is_gimple_id (t) || handled_component_p (t)
 is_gimple_addressable (tree t)
 {
   return (is_gimple_id (t) || handled_component_p (t)
-         || TREE_CODE (t) == REALPART_EXPR
-         || TREE_CODE (t) == IMAGPART_EXPR
-         || TREE_CODE (t) == INDIRECT_REF);
+         || INDIRECT_REF_P (t));
 }
 
 }
 
-/* Return true if T is function invariant.  Or rather a restricted
+/* Return true if T is a GIMPLE minimal invariant.  It's a restricted
    form of function invariant.  */
 
 bool
    form of function invariant.  */
 
 bool
-is_gimple_min_invariant (tree t)
+is_gimple_min_invariant (const_tree t)
 {
   switch (TREE_CODE (t))
     {
 {
   switch (TREE_CODE (t))
     {
@@ -340,10 +180,18 @@ is_gimple_min_invariant (tree t)
 
     case INTEGER_CST:
     case REAL_CST:
 
     case INTEGER_CST:
     case REAL_CST:
+    case FIXED_CST:
     case STRING_CST:
     case COMPLEX_CST:
     case VECTOR_CST:
     case STRING_CST:
     case COMPLEX_CST:
     case VECTOR_CST:
-      return !TREE_OVERFLOW (t);
+      return true;
+
+    /* Vector constant constructors are gimple invariant.  */
+    case CONSTRUCTOR:
+      if (TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+       return TREE_CONSTANT (t);
+      else
+       return false;
 
     default:
       return false;
 
     default:
       return false;
@@ -355,13 +203,14 @@ is_gimple_min_invariant (tree t)
 bool
 is_gimple_stmt (tree t)
 {
 bool
 is_gimple_stmt (tree t)
 {
-  enum tree_code code = TREE_CODE (t);
-
-  if (IS_EMPTY_STMT (t))
-    return 1;
+  const enum tree_code code = TREE_CODE (t);
 
   switch (code)
     {
 
   switch (code)
     {
+    case NOP_EXPR:
+      /* The only valid NOP_EXPR is the empty statement.  */
+      return IS_EMPTY_STMT (t);
+
     case BIND_EXPR:
     case COND_EXPR:
       /* These are only valid if they're void.  */
     case BIND_EXPR:
     case COND_EXPR:
       /* These are only valid if they're void.  */
@@ -376,15 +225,29 @@ is_gimple_stmt (tree t)
     case TRY_FINALLY_EXPR:
     case EH_FILTER_EXPR:
     case CATCH_EXPR:
     case TRY_FINALLY_EXPR:
     case EH_FILTER_EXPR:
     case CATCH_EXPR:
+    case CHANGE_DYNAMIC_TYPE_EXPR:
     case ASM_EXPR:
     case RESX_EXPR:
     case PHI_NODE:
     case STATEMENT_LIST:
     case ASM_EXPR:
     case RESX_EXPR:
     case PHI_NODE:
     case STATEMENT_LIST:
+    case OMP_PARALLEL:
+    case OMP_FOR:
+    case OMP_SECTIONS:
+    case OMP_SECTIONS_SWITCH:
+    case OMP_SECTION:
+    case OMP_SINGLE:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+    case OMP_CRITICAL:
+    case OMP_RETURN:
+    case OMP_CONTINUE:
+    case OMP_ATOMIC_LOAD:
+    case OMP_ATOMIC_STORE:
       /* These are always void.  */
       return true;
 
     case CALL_EXPR:
       /* These are always void.  */
       return true;
 
     case CALL_EXPR:
-    case MODIFY_EXPR:
+    case GIMPLE_MODIFY_STMT:
       /* These are valid regardless of their type.  */
       return true;
 
       /* These are valid regardless of their type.  */
       return true;
 
@@ -406,7 +269,7 @@ is_gimple_variable (tree t)
 
 /*  Return true if T is a GIMPLE identifier (something with an address).  */
 
 
 /*  Return true if T is a GIMPLE identifier (something with an address).  */
 
-static inline bool
+bool
 is_gimple_id (tree t)
 {
   return (is_gimple_variable (t)
 is_gimple_id (tree t)
 {
   return (is_gimple_variable (t)
@@ -422,12 +285,16 @@ is_gimple_id (tree t)
 bool
 is_gimple_reg_type (tree type)
 {
 bool
 is_gimple_reg_type (tree type)
 {
-  return (!AGGREGATE_TYPE_P (type)
-          && TREE_CODE (type) != COMPLEX_TYPE);
-}
+  /* In addition to aggregate types, we also exclude complex types if not
+     optimizing because they can be subject to partial stores in GNU C by
+     means of the __real__ and __imag__ operators and we cannot promote
+     them to total stores (see gimplify_modify_expr_complex_part).  */
+  return !(AGGREGATE_TYPE_P (type)
+          || (TREE_CODE (type) == COMPLEX_TYPE && !optimize));
 
 
+}
 
 
-/* Return true if T is a scalar register variable.  */
+/* Return true if T is a non-aggregate register variable.  */
 
 bool
 is_gimple_reg (tree t)
 
 bool
 is_gimple_reg (tree t)
@@ -435,19 +302,56 @@ is_gimple_reg (tree t)
   if (TREE_CODE (t) == SSA_NAME)
     t = SSA_NAME_VAR (t);
 
   if (TREE_CODE (t) == SSA_NAME)
     t = SSA_NAME_VAR (t);
 
-  return (is_gimple_variable (t)
-         && is_gimple_reg_type (TREE_TYPE (t))
-         /* A volatile decl is not acceptable because we can't reuse it as
-            needed.  We need to copy it into a temp first.  */
-         && ! TREE_THIS_VOLATILE (t)
-         && ! needs_to_live_in_memory (t));
+  if (MTAG_P (t))
+    return false;
+
+  if (!is_gimple_variable (t))
+    return false;
+
+  if (!is_gimple_reg_type (TREE_TYPE (t)))
+    return false;
+
+  /* A volatile decl is not acceptable because we can't reuse it as
+     needed.  We need to copy it into a temp first.  */
+  if (TREE_THIS_VOLATILE (t))
+    return false;
+
+  /* We define "registers" as things that can be renamed as needed,
+     which with our infrastructure does not apply to memory.  */
+  if (needs_to_live_in_memory (t))
+    return false;
+
+  /* Hard register variables are an interesting case.  For those that
+     are call-clobbered, we don't know where all the calls are, since
+     we don't (want to) take into account which operations will turn
+     into libcalls at the rtl level.  For those that are call-saved,
+     we don't currently model the fact that calls may in fact change
+     global hard registers, nor do we examine ASM_CLOBBERS at the tree
+     level, and so miss variable changes that might imply.  All around,
+     it seems safest to not do too much optimization with these at the
+     tree level at all.  We'll have to rely on the rtl optimizers to
+     clean this up, as there we've got all the appropriate bits exposed.  */
+  if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+    return false;
+
+  /* Complex and vector values must have been put into SSA-like form.
+     That is, no assignments to the individual components.  */
+  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+      || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+    return DECL_GIMPLE_REG_P (t);
+
+  return true;
 }
 
 }
 
+
 /* Returns true if T is a GIMPLE formal temporary variable.  */
 
 bool
 is_gimple_formal_tmp_var (tree t)
 {
 /* Returns true if T is a GIMPLE formal temporary variable.  */
 
 bool
 is_gimple_formal_tmp_var (tree t)
 {
+  if (TREE_CODE (t) == SSA_NAME)
+    return true;
+
   return TREE_CODE (t) == VAR_DECL && DECL_GIMPLE_FORMAL_TEMP_P (t);
 }
 
   return TREE_CODE (t) == VAR_DECL && DECL_GIMPLE_FORMAL_TEMP_P (t);
 }
 
@@ -494,11 +398,21 @@ is_gimple_val (tree t)
   /* FIXME make these decls.  That can happen only when we expose the
      entire landing-pad construct at the tree level.  */
   if (TREE_CODE (t) == EXC_PTR_EXPR || TREE_CODE (t) == FILTER_EXPR)
   /* FIXME make these decls.  That can happen only when we expose the
      entire landing-pad construct at the tree level.  */
   if (TREE_CODE (t) == EXC_PTR_EXPR || TREE_CODE (t) == FILTER_EXPR)
-    return 1;
+    return true;
 
   return (is_gimple_variable (t) || is_gimple_min_invariant (t));
 }
 
 
   return (is_gimple_variable (t) || is_gimple_min_invariant (t));
 }
 
+/* Similarly, but accept hard registers as inputs to asm statements.  */
+
+bool
+is_gimple_asm_val (tree t)
+{
+  if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+    return true;
+
+  return is_gimple_val (t);
+}
 
 /* Return true if T is a GIMPLE minimal lvalue.  */
 
 
 /* Return true if T is a GIMPLE minimal lvalue.  */
 
@@ -516,13 +430,10 @@ is_gimple_cast (tree t)
 {
   return (TREE_CODE (t) == NOP_EXPR
          || TREE_CODE (t) == CONVERT_EXPR
 {
   return (TREE_CODE (t) == NOP_EXPR
          || TREE_CODE (t) == CONVERT_EXPR
-          || TREE_CODE (t) == FIX_TRUNC_EXPR
-          || TREE_CODE (t) == FIX_CEIL_EXPR
-          || TREE_CODE (t) == FIX_FLOOR_EXPR
-          || TREE_CODE (t) == FIX_ROUND_EXPR);
+          || TREE_CODE (t) == FIX_TRUNC_EXPR);
 }
 
 }
 
-/* Return true if T is a valid op0 of a CALL_EXPR.  */
+/* Return true if T is a valid function operand of a CALL_EXPR.  */
 
 bool
 is_gimple_call_addr (tree t)
 
 bool
 is_gimple_call_addr (tree t)
@@ -537,8 +448,10 @@ is_gimple_call_addr (tree t)
 tree
 get_call_expr_in (tree t)
 {
 tree
 get_call_expr_in (tree t)
 {
-  if (TREE_CODE (t) == MODIFY_EXPR)
-    t = TREE_OPERAND (t, 1);
+  /* FIXME tuples: delete the assertion below when conversion complete.  */
+  gcc_assert (TREE_CODE (t) != MODIFY_EXPR);
+  if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
+    t = GIMPLE_STMT_OPERAND (t, 1);
   if (TREE_CODE (t) == WITH_SIZE_EXPR)
     t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == CALL_EXPR)
   if (TREE_CODE (t) == WITH_SIZE_EXPR)
     t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == CALL_EXPR)
@@ -546,22 +459,25 @@ get_call_expr_in (tree t)
   return NULL_TREE;
 }
 
   return NULL_TREE;
 }
 
-/* Given a memory reference expression, return the base address.  Note that,
-   in contrast with get_base_var, this will not recurse inside INDIRECT_REF
-   expressions.  Therefore, given the reference PTR->FIELD, this function
-   will return *PTR.  Whereas get_base_var would've returned PTR.  */
+/* Given a memory reference expression T, return its base address.
+   The base address of a memory reference expression is the main
+   object being referenced.  For instance, the base address for
+   'array[i].fld[j]' is 'array'.  You can think of this as stripping
+   away the offset part from a memory address.
+
+   This function calls handled_component_p to strip away all the inner
+   parts of the memory reference until it reaches the base object.  */
 
 tree
 get_base_address (tree t)
 {
 
 tree
 get_base_address (tree t)
 {
-  while (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR
-        || handled_component_p (t))
+  while (handled_component_p (t))
     t = TREE_OPERAND (t, 0);
   
   if (SSA_VAR_P (t)
       || TREE_CODE (t) == STRING_CST
       || TREE_CODE (t) == CONSTRUCTOR
     t = TREE_OPERAND (t, 0);
   
   if (SSA_VAR_P (t)
       || TREE_CODE (t) == STRING_CST
       || TREE_CODE (t) == CONSTRUCTOR
-      || TREE_CODE (t) == INDIRECT_REF)
+      || INDIRECT_REF_P (t))
     return t;
   else
     return NULL_TREE;
     return t;
   else
     return NULL_TREE;
@@ -571,16 +487,16 @@ void
 recalculate_side_effects (tree t)
 {
   enum tree_code code = TREE_CODE (t);
 recalculate_side_effects (tree t)
 {
   enum tree_code code = TREE_CODE (t);
-  int fro = first_rtl_op (code);
+  int len = TREE_OPERAND_LENGTH (t);
   int i;
 
   switch (TREE_CODE_CLASS (code))
     {
   int i;
 
   switch (TREE_CODE_CLASS (code))
     {
-    case 'e':
+    case tcc_expression:
       switch (code)
        {
        case INIT_EXPR:
       switch (code)
        {
        case INIT_EXPR:
-       case MODIFY_EXPR:
+       case GIMPLE_MODIFY_STMT:
        case VA_ARG_EXPR:
        case PREDECREMENT_EXPR:
        case PREINCREMENT_EXPR:
        case VA_ARG_EXPR:
        case PREDECREMENT_EXPR:
        case PREINCREMENT_EXPR:
@@ -595,17 +511,66 @@ recalculate_side_effects (tree t)
        }
       /* Fall through.  */
 
        }
       /* Fall through.  */
 
-    case '<':  /* a comparison expression */
-    case '1':  /* a unary arithmetic expression */
-    case '2':  /* a binary arithmetic expression */
-    case 'r':  /* a reference */
+    case tcc_comparison:  /* a comparison expression */
+    case tcc_unary:       /* a unary arithmetic expression */
+    case tcc_binary:      /* a binary arithmetic expression */
+    case tcc_reference:   /* a reference */
+    case tcc_vl_exp:        /* a function call */
       TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t);
       TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t);
-      for (i = 0; i < fro; ++i)
+      for (i = 0; i < len; ++i)
        {
          tree op = TREE_OPERAND (t, i);
          if (op && TREE_SIDE_EFFECTS (op))
            TREE_SIDE_EFFECTS (t) = 1;
        }
       break;
        {
          tree op = TREE_OPERAND (t, i);
          if (op && TREE_SIDE_EFFECTS (op))
            TREE_SIDE_EFFECTS (t) = 1;
        }
       break;
+
+    default:
+      /* Can never be used with non-expressions.  */
+      gcc_unreachable ();
    }
 }
    }
 }
+
+/* Canonicalize a tree T for use in a COND_EXPR as conditional.  Returns
+   a canonicalized tree that is valid for a COND_EXPR or NULL_TREE, if
+   we failed to create one.  */
+
+tree
+canonicalize_cond_expr_cond (tree t)
+{
+  /* For (bool)x use x != 0.  */
+  if (TREE_CODE (t) == NOP_EXPR
+      && TREE_TYPE (t) == boolean_type_node)
+    {
+      tree top0 = TREE_OPERAND (t, 0);
+      t = build2 (NE_EXPR, TREE_TYPE (t),
+                 top0, build_int_cst (TREE_TYPE (top0), 0));
+    }
+  /* For !x use x == 0.  */
+  else if (TREE_CODE (t) == TRUTH_NOT_EXPR)
+    {
+      tree top0 = TREE_OPERAND (t, 0);
+      t = build2 (EQ_EXPR, TREE_TYPE (t),
+                 top0, build_int_cst (TREE_TYPE (top0), 0));
+    }
+  /* For cmp ? 1 : 0 use cmp.  */
+  else if (TREE_CODE (t) == COND_EXPR
+          && COMPARISON_CLASS_P (TREE_OPERAND (t, 0))
+          && integer_onep (TREE_OPERAND (t, 1))
+          && integer_zerop (TREE_OPERAND (t, 2)))
+    {
+      tree top0 = TREE_OPERAND (t, 0);
+      t = build2 (TREE_CODE (top0), TREE_TYPE (t),
+                 TREE_OPERAND (top0, 0), TREE_OPERAND (top0, 1));
+    }
+
+  /* A valid conditional for a COND_EXPR is either a gimple value
+     or a comparison with two gimple value operands.  */
+  if (is_gimple_val (t)
+      || (COMPARISON_CLASS_P (t)
+         && is_gimple_val (TREE_OPERAND (t, 0))
+         && is_gimple_val (TREE_OPERAND (t, 1))))
+    return t;
+
+  return NULL_TREE;
+}