Ejemplo n.º 1
0
PhiNode*
new_phi_node(int src_count)
{
    PhiNode *phi = create_phi_node(the_suif_env, NULL, false);

    while (src_count-- > 0)
	phi->append_src(NULL);

    return phi;
}
Ejemplo n.º 2
0
static tree
create_tailcall_accumulator (const char *label, basic_block bb, tree init)
{
  tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl));
  if (POINTER_TYPE_P (ret_type))
    ret_type = sizetype;

  tree tmp = make_temp_ssa_name (ret_type, NULL, label);
  gimple phi;

  phi = create_phi_node (tmp, bb);
  /* RET_TYPE can be a float when -ffast-maths is enabled.  */
  add_phi_arg (phi, fold_convert (ret_type, init), single_pred_edge (bb),
	       UNKNOWN_LOCATION);
  return PHI_RESULT (phi);
}
Ejemplo n.º 3
0
static gphi *
input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
	   struct function *fn)
{
  unsigned HOST_WIDE_INT ix;
  tree phi_result;
  int i, len;
  gphi *result;

  ix = streamer_read_uhwi (ib);
  phi_result = (*SSANAMES (fn))[ix];
  len = EDGE_COUNT (bb->preds);
  result = create_phi_node (phi_result, bb);

  /* We have to go through a lookup process here because the preds in the
     reconstructed graph are generally in a different order than they
     were in the original program.  */
  for (i = 0; i < len; i++)
    {
      tree def = stream_read_tree (ib, data_in);
      int src_index = streamer_read_uhwi (ib);
      bitpack_d bp = streamer_read_bitpack (ib);
      /* Do not cache a location - we do not have API to get pointer to the
	 location in PHI statement and we may trigger reallocation.  */
      location_t arg_loc = stream_input_location_now (&bp, data_in);
      basic_block sbb = BASIC_BLOCK_FOR_FN (fn, src_index);

      edge e = NULL;
      int j;

      for (j = 0; j < len; j++)
	if (EDGE_PRED (bb, j)->src == sbb)
	  {
	    e = EDGE_PRED (bb, j);
	    break;
	  }

      add_phi_arg (result, def, e, arg_loc);
    }

  return result;
}
Ejemplo n.º 4
0
static gimple
input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
	   struct function *fn)
{
  unsigned HOST_WIDE_INT ix;
  tree phi_result;
  int i, len;
  gimple result;

  ix = streamer_read_uhwi (ib);
  phi_result = VEC_index (tree, SSANAMES (fn), ix);
  len = EDGE_COUNT (bb->preds);
  result = create_phi_node (phi_result, bb);
  SSA_NAME_DEF_STMT (phi_result) = result;

  /* We have to go through a lookup process here because the preds in the
     reconstructed graph are generally in a different order than they
     were in the original program.  */
  for (i = 0; i < len; i++)
    {
      tree def = stream_read_tree (ib, data_in);
      int src_index = streamer_read_uhwi (ib);
      location_t arg_loc = lto_input_location (ib, data_in);
      basic_block sbb = BASIC_BLOCK_FOR_FUNCTION (fn, src_index);

      edge e = NULL;
      int j;

      for (j = 0; j < len; j++)
	if (EDGE_PRED (bb, j)->src == sbb)
	  {
	    e = EDGE_PRED (bb, j);
	    break;
	  }

      add_phi_arg (result, def, e, arg_loc);
    }

  return result;
}
Ejemplo n.º 5
0
DesignFlowStep_Status compute_implicit_calls::InternalExec()
{
   tree_nodeRef node = TM->get_tree_node_const(function_id);
   function_decl * fd = GetPointer<function_decl>(node);
   if (!fd || !fd->body)
   {
      PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Node is not a function or it hasn't a body");
      return DesignFlowStep_Status::UNCHANGED;
   }
   bool changed = false;
   std::list<std::pair<tree_nodeRef, unsigned int>> to_be_lowered_memset;

   unsigned int max_loop_id = 0;

   statement_list * sl = GetPointer<statement_list>(GET_NODE(fd->body));
   THROW_ASSERT(sl, "Body is not a statement_list");
   std::map<unsigned int, blocRef>::iterator it_bb, it_bb_end = sl->list_of_bloc.end();
   for(it_bb = sl->list_of_bloc.begin(); it_bb != it_bb_end ; it_bb++)
   {
      if (it_bb->second->number == BB_ENTRY || it_bb->second->number == BB_EXIT)
         continue;
      max_loop_id = std::max(max_loop_id, it_bb->second->loop_id);
      for(const auto stmt : it_bb->second->CGetStmtList())
      {
         tree_nodeRef tn = GET_NODE(stmt);
         if(tn->get_kind() == gimple_assign_K)
         {
            gimple_assign* gm = GetPointer<gimple_assign>(tn);
            INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing node " + tn->ToString());

            /// check for implicit memset/memcpy calls
            tree_nodeRef op0 = GET_NODE(gm->op0);
            tree_nodeRef op1 = GET_NODE(gm->op1);
            unsigned int op0_type_index, op1_type_index;
            tree_nodeRef op0_type = tree_helper::get_type_node(op0, op0_type_index);
            tree_nodeRef op1_type = tree_helper::get_type_node(op1, op1_type_index);

            bool is_a_vector_bitfield = false;
            if(op1->get_kind() == bit_field_ref_K)
            {
               bit_field_ref* bfr = GetPointer<bit_field_ref>(op1);
               if(tree_helper::is_a_vector(TM, GET_INDEX_NODE(bfr->op0)))
                  is_a_vector_bitfield = true;
            }

            bool load_candidate = (op1->get_kind() == bit_field_ref_K && !is_a_vector_bitfield) ||op1->get_kind() == component_ref_K || op1->get_kind() == indirect_ref_K || op1->get_kind() == misaligned_indirect_ref_K || op1->get_kind() == mem_ref_K || op1->get_kind() == array_ref_K || op1->get_kind() == target_mem_ref_K || op1->get_kind() == target_mem_ref461_K;
            if(op1->get_kind() == realpart_expr_K || op1->get_kind() == imagpart_expr_K)
            {
               enum kind code1 = GET_NODE(GetPointer<unary_expr>(op1)->op)->get_kind();
               if((code1 == bit_field_ref_K && !is_a_vector_bitfield) ||
                     code1 == component_ref_K || code1 == indirect_ref_K || code1 == bit_field_ref_K ||
                     code1 == misaligned_indirect_ref_K || code1 == mem_ref_K || code1 == array_ref_K ||
                     code1 == target_mem_ref_K || code1 == target_mem_ref461_K)
                  load_candidate = true;
               if(code1 == var_decl_K)
                  load_candidate = true;
            }
            bool store_candidate = op0->get_kind() == bit_field_ref_K || op0->get_kind() == component_ref_K || op0->get_kind() == indirect_ref_K || op0->get_kind() == misaligned_indirect_ref_K || op0->get_kind() == mem_ref_K || op0->get_kind() == array_ref_K || op0->get_kind() == target_mem_ref_K || op0->get_kind() == target_mem_ref461_K;
            if(op0->get_kind() == realpart_expr_K || op0->get_kind() == imagpart_expr_K)
            {
               enum kind code0 = GET_NODE(GetPointer<unary_expr>(op0)->op)->get_kind();
               if(code0 == component_ref_K || code0 == indirect_ref_K || code0 == bit_field_ref_K ||
                     code0 == misaligned_indirect_ref_K || code0 == mem_ref_K || code0 == array_ref_K ||
                     code0 == target_mem_ref_K || code0 == target_mem_ref461_K)
                  store_candidate = true;
               if(code0 == var_decl_K)
                  store_candidate = true;
            }
            if(!gm->clobber && !gm->init_assignment && op0_type && op1_type &&
                  ((op0_type->get_kind()== record_type_K && op1_type->get_kind()== record_type_K && op1->get_kind() != view_convert_expr_K) ||
                   (op0_type->get_kind()== union_type_K && op1_type->get_kind()== union_type_K && op1->get_kind() != view_convert_expr_K) ||
                   (op0_type->get_kind() == array_type_K) ||
                   (store_candidate && load_candidate)
                   )
                  )
            {
               changed = true;
               if(op1->get_kind() == constructor_K && GetPointer<constructor>(op1) && GetPointer<constructor>(op1)->list_of_idx_valu.size() == 0)
               {
                  mem_ref * mr = GetPointer<mem_ref>(op0);
                  THROW_ASSERT(mr, "unexpected condition");
                  unsigned int var = tree_helper::get_base_index(TM, GET_INDEX_NODE(mr->op0));
                  bool do_lowering = var != 0;
                  if(do_lowering)
                  {
                     auto type_index = tree_helper::get_type_index(TM, var);
                     const auto type_node = TM->get_tree_node_const(type_index);
                     do_lowering = type_node->get_kind() == array_type_K;
                     if(do_lowering)
                     {
                        const auto element_type = tree_helper::CGetElements(type_node);
                        const auto element_type_kind = element_type->get_kind();
                        if(not (element_type_kind == boolean_type_K or element_type_kind == CharType_K or element_type_kind == enumeral_type_K or element_type_kind == integer_type_K or element_type_kind == pointer_type_K or element_type_kind == record_type_K))
                        {
                           do_lowering = false;
                           THROW_ASSERT(element_type_kind == array_type_K
                                 or element_type_kind == nullptr_type_K
                                 or element_type_kind == type_pack_expansion_K
                                 or element_type_kind == complex_type_K
                                 or element_type_kind == function_type_K
                                 or element_type_kind == lang_type_K
                                 or element_type_kind == method_type_K
                                 or element_type_kind == offset_type_K
                                 or element_type_kind == qual_union_type_K
                                 or element_type_kind == record_type_K
                                 or element_type_kind == reference_type_K
                                 or element_type_kind == set_type_K
                                 or element_type_kind == template_type_parm_K
                                 or element_type_kind == typename_type_K
                                 or element_type_kind == union_type_K
                                 or element_type_kind == vector_type_K
                                 or element_type_kind == void_type_K,
                                 element_type->get_kind_text());
                        }
                     }
                  }
                  if(do_lowering)
                     to_be_lowered_memset.push_front(std::make_pair(stmt,it_bb->second->number));
                  else
                  {
                     unsigned int memset_function_id = TM->function_index("__builtin_memset");
                     THROW_ASSERT(AppM->GetFunctionBehavior(memset_function_id)->GetBehavioralHelper()->has_implementation(), "inconsistent behavioral helper");
                     AppM->GetCallGraphManager()->AddCallPoint(function_id, memset_function_id, GET_INDEX_NODE(stmt), FunctionEdgeInfo::CallType::direct_call);
                  }
               }
               else
               {
                  unsigned int memcpy_function_id = TM->function_index("__builtin_memcpy");
                  THROW_ASSERT(AppM->GetFunctionBehavior(memcpy_function_id)->GetBehavioralHelper()->has_implementation(), "inconsistent behavioral helper");
                  AppM->GetCallGraphManager()->AddCallPoint(function_id, memcpy_function_id, GET_INDEX_NODE(stmt), FunctionEdgeInfo::CallType::direct_call);
               }
            }
            INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Analyzed node " + tn->ToString());
         }
      }
   }

   /// do the memset transformations
   for(auto stmt_bb_pair : to_be_lowered_memset)
   {
      INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Transforming (" + STR(stmt_bb_pair.first->index) + ")" + STR(stmt_bb_pair.first));
      auto BB1_index = stmt_bb_pair.second;
      auto BB1_block = sl->list_of_bloc[BB1_index];

      ///create BBN1
      const auto BBN1_block_index  = (sl->list_of_bloc.rbegin())->first + 1;
      INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Created BB" + STR(BBN1_block_index));
      auto BBN1_block = blocRef(new bloc(BBN1_block_index));
      sl->list_of_bloc[BBN1_block_index] = BBN1_block;

      max_loop_id++;
      BBN1_block->loop_id = max_loop_id;
      BBN1_block->schedule = BB1_block->schedule;

      ///Add BBN1 predecessor as BB1_index basic block
      BBN1_block->list_of_pred.push_back(BB1_index);
      BBN1_block->list_of_pred.push_back(BBN1_block_index);

      ///create BBN2
      const auto BBN2_block_index  = (sl->list_of_bloc.rbegin())->first + 1;
      INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Created BB" + STR(BBN2_block_index));
      auto BBN2_block = blocRef(new bloc(BBN2_block_index));
      sl->list_of_bloc[BBN2_block_index] = BBN2_block;

      BBN2_block->loop_id = BB1_block->loop_id;
      BBN2_block->schedule = BB1_block->schedule;

      ///Add BBN2 predecessor as BBN1 basic block
      BBN2_block->list_of_pred.push_back(BBN1_block_index);
      ///Add BBN2 successor as BB1 basic block
      BBN2_block->list_of_succ = BB1_block->list_of_succ;
      /// fix true and false edges
      BBN2_block->true_edge = BB1_block->true_edge;
      BB1_block->true_edge = 0;
      BBN2_block->false_edge = BB1_block->false_edge;
      BB1_block->false_edge = 0;
      BB1_block->list_of_succ.clear();
      BB1_block->list_of_succ.push_back(BBN1_block_index);
      ///Add BBN1 successor as succ basic block
      BBN1_block->list_of_succ.push_back(BBN1_block_index);
      BBN1_block->true_edge = BBN1_block_index;
      BBN1_block->list_of_succ.push_back(BBN2_block_index);
      BBN1_block->false_edge = BBN2_block_index;

      /// Fix BBN2 successors
      for(auto succ: BBN2_block->list_of_succ)
      {
         auto succ_block = sl->list_of_bloc[succ];
         succ_block->list_of_pred.erase(std::find(succ_block->list_of_pred.begin(), succ_block->list_of_pred.end(), BB1_index));
         succ_block->list_of_pred.push_back(BBN2_block_index);
         ///Update all the phis
         for(auto & phi : succ_block->CGetPhiList())
         {
            auto gp = GetPointer<gimple_phi>(GET_NODE(phi));
            for(auto & def_edge : gp->CGetDefEdgesList())
            {
               if(def_edge.second == BB1_index)
               {
                  gp->ReplaceDefEdge(TM, def_edge, gimple_phi::DefEdge(def_edge.first, BBN2_block_index));
               }
            }
         }
      }
      ///The tree manipulation
      auto tree_man = tree_manipulationRef(new tree_manipulation(TM, parameters));

      /// retrive the starting variable
      gimple_assign* ga = GetPointer<gimple_assign>(GET_NODE(stmt_bb_pair.first));
      mem_ref * mr = GetPointer<mem_ref>(GET_NODE(ga->op0));
      unsigned int var = tree_helper::get_base_index(TM, GET_INDEX_NODE(mr->op0));
      tree_nodeRef init_var = mr->op0;
      const std::string srcp_default = ga->include_name + ":" + STR(ga->line_number) + ":" + STR(ga->column_number);
      auto type_index = tree_helper::get_type_index(TM, var);
      tree_nodeConstRef type_node = TM->CGetTreeNode(type_index);
      THROW_ASSERT(type_node->get_kind() == array_type_K, "unexpected condition");
      while (type_node->get_kind() == array_type_K)
         type_node = tree_helper::CGetElements(type_node);
      tree_nodeRef offset_type = tree_man->create_size_type();
      tree_nodeRef pt = tree_man->create_pointer_type(type_node);

      /// add a cast
      tree_nodeRef nop_init_var = tree_man->create_unary_operation(pt, init_var, srcp_default, nop_expr_K);
      tree_nodeRef nop_init_var_ga = tree_man->CreateGimpleAssign(pt, nop_init_var, BB1_index, srcp_default);
      init_var = GetPointer<gimple_assign>(GET_NODE(nop_init_var_ga))->op0;
      INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding cast statement " + GET_NODE(nop_init_var_ga)->ToString());

      ///Create phi for the induction variable of BBN1
      tree_nodeRef new_induction_var;
      ///The list of def edge which contains for the moment only the value coming from the forward edge
      std::vector<std::pair<tree_nodeRef, unsigned int> > list_of_def_edge;
      list_of_def_edge.push_back(std::pair<tree_nodeRef, unsigned int>(init_var, BB1_index));
      auto phi = tree_man->create_phi_node(new_induction_var, list_of_def_edge, BBN1_block_index);
      BBN1_block->AddPhi(phi);
      gimple_phi* gp = GetPointer<gimple_phi>(GET_NODE(phi));
      GetPointer<ssa_name>(GET_NODE(gp->res))->use_set = PointToSolutionRef(new PointToSolution());
      GetPointer<ssa_name>(GET_NODE(gp->res))->use_set->variables.push_back(TM->GetTreeReindex(var));

      /// compute the size of memory to be set with memset
      const auto dst_type = tree_helper::CGetType(GET_NODE(mr->op0));
      const pointer_type * dst_ptr_t = GetPointer<const pointer_type>(dst_type);
      THROW_ASSERT(dst_ptr_t, "unexpected condition");
      const auto dst_size = tree_helper::Size(dst_ptr_t->ptd);
      THROW_ASSERT(dst_size % 8 == 0, "unexpected condition");
      const auto copy_byte_size = dst_size / 8;
      tree_nodeRef copy_byte_size_node = TM->CreateUniqueIntegerCst(static_cast<long long int >(copy_byte_size), GET_INDEX_NODE(offset_type));
      tree_nodeRef pp = tree_man->create_binary_operation(pt, init_var, copy_byte_size_node, srcp_default, pointer_plus_expr_K);
      tree_nodeRef pp_ga = tree_man->CreateGimpleAssign(pt, pp, BB1_index, srcp_default);
      GetPointer<gimple_assign>(GET_NODE(pp_ga))->temporary_address = true;
      tree_nodeRef vd_limit = GetPointer<gimple_assign>(GET_NODE(pp_ga))->op0;
      GetPointer<ssa_name>(GET_NODE(vd_limit))->use_set = PointToSolutionRef(new PointToSolution());
      GetPointer<ssa_name>(GET_NODE(vd_limit))->use_set->variables.push_back(TM->GetTreeReindex(var));

      INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(pp_ga)->ToString());
      tree_nodeRef size_node = TM->CreateUniqueIntegerCst(static_cast<long long int >(tree_helper::Size(type_node)/8), GET_INDEX_NODE(offset_type));
      tree_nodeRef pp_ind = tree_man->create_binary_operation(pt, gp->res, size_node, srcp_default, pointer_plus_expr_K);
      tree_nodeRef pp_ga_ind = tree_man->CreateGimpleAssign(pt, pp_ind, BBN1_block_index, srcp_default);
      GetPointer<gimple_assign>(GET_NODE(pp_ga_ind))->temporary_address = true;
      BBN1_block->PushBack(pp_ga_ind);
      tree_nodeRef vd_ind = GetPointer<gimple_assign>(GET_NODE(pp_ga_ind))->op0;
      GetPointer<ssa_name>(GET_NODE(vd_ind))->use_set = PointToSolutionRef(new PointToSolution());
      GetPointer<ssa_name>(GET_NODE(vd_ind))->use_set->variables.push_back(TM->GetTreeReindex(var));
      INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(pp_ga_ind)->ToString());
      GetPointer<gimple_phi>(GET_NODE(phi))->AddDefEdge(TM, gimple_phi::DefEdge(vd_ind, BBN1_block_index));

      /// the comparison
      const auto boolean_type = tree_man->create_boolean_type();
      const auto comparison = tree_man->create_binary_operation(boolean_type, vd_ind, vd_limit, srcp_default, ne_expr_K);
      tree_nodeRef comp_ga = tree_man->CreateGimpleAssign(boolean_type, comparison, BBN1_block_index, srcp_default);
      BBN1_block->PushBack(comp_ga);
      tree_nodeRef comp_res = GetPointer<gimple_assign>(GET_NODE(comp_ga))->op0;
      INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---comparison assign " + STR(comp_ga));

      /// the gimple cond
      const auto gc = tree_man->create_gimple_cond(comp_res, srcp_default, BBN1_block_index);
      INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---gimple cond " + STR(gc));

      /// restructure of the implicit memset statement
      tree_nodeRef zero_offset = TM->CreateUniqueIntegerCst(0, GET_INDEX_NODE(pt));
      tree_nodeRef new_mem_ref = tree_man->create_binary_operation(TM->GetTreeReindex(type_node->index), gp->res, zero_offset, srcp_default, mem_ref_K);
      ga->op0 = new_mem_ref;
      tree_nodeRef zero_value = TM->CreateUniqueIntegerCst(0, type_node->index);
      ga->op1 = zero_value;

      const auto list_of_stmt = BB1_block->CGetStmtList();
      bool found_memset_statement = false;
      ///We must use pointer since we are erasing elements in the list
      for(auto statement = list_of_stmt.begin(); statement != list_of_stmt.end(); statement++)
      {
         if(GET_INDEX_NODE(*statement) == GET_INDEX_CONST_NODE(stmt_bb_pair.first))
         {
            /// move var = {}; to BBN1
            found_memset_statement = true;
            const auto temp_statement = *statement;
            ///Going one step step forward to avoid invalidation of the pointer
            statement++;
            ///Moving statement
            BB1_block->RemoveStmt(temp_statement);
            BBN1_block->PushBack(temp_statement);
            ///Going one step back since pointer is already increment in for loop
            statement--;
         }
         else if(found_memset_statement)
         {
            /// move (xxxxb)* to BBN2
            const auto temp_statement = *statement;
            ///Going one step step forward to avoid invalidation of the pointer
            statement++;
            ///Moving statement
            BB1_block->RemoveStmt(temp_statement);
            BBN2_block->PushBack(temp_statement);
            ///Going one step back since pointer is already increment in for loop
            statement--;
         }
      }
      THROW_ASSERT(found_memset_statement, "unexpected condition");
      BB1_block->PushBack(nop_init_var_ga);
      BB1_block->PushBack(pp_ga);
      BBN1_block->PushBack(gc);
      INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Transformed " + STR(stmt_bb_pair.first));
   }
   if (debug_level >= DEBUG_LEVEL_PEDANTIC or parameters->getOption<bool>(OPT_print_dot))
      AppM->CGetCallGraphManager()->CGetCallGraph()->WriteDot("compute_implicit_calls" + GetSignature() + ".dot");
   return changed ? DesignFlowStep_Status::SUCCESS : DesignFlowStep_Status::UNCHANGED;
}
Ejemplo n.º 6
0
static bool
factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
				   tree arg0, tree arg1)
{
  gimple arg0_def_stmt = NULL, arg1_def_stmt = NULL, new_stmt;
  tree new_arg0 = NULL_TREE, new_arg1 = NULL_TREE;
  tree temp, result;
  gphi *newphi;
  gimple_stmt_iterator gsi, gsi_for_def;
  source_location locus = gimple_location (phi);
  enum tree_code convert_code;

  /* Handle only PHI statements with two arguments.  TODO: If all
     other arguments to PHI are INTEGER_CST or if their defining
     statement have the same unary operation, we can handle more
     than two arguments too.  */
  if (gimple_phi_num_args (phi) != 2)
    return false;

  /* First canonicalize to simplify tests.  */
  if (TREE_CODE (arg0) != SSA_NAME)
    {
      std::swap (arg0, arg1);
      std::swap (e0, e1);
    }

  if (TREE_CODE (arg0) != SSA_NAME
      || (TREE_CODE (arg1) != SSA_NAME
	  && TREE_CODE (arg1) != INTEGER_CST))
    return false;

  /* Check if arg0 is an SSA_NAME and the stmt which defines arg0 is
     a conversion.  */
  arg0_def_stmt = SSA_NAME_DEF_STMT (arg0);
  if (!is_gimple_assign (arg0_def_stmt)
      || !gimple_assign_cast_p (arg0_def_stmt))
    return false;

  /* Use the RHS as new_arg0.  */
  convert_code = gimple_assign_rhs_code (arg0_def_stmt);
  new_arg0 = gimple_assign_rhs1 (arg0_def_stmt);
  if (convert_code == VIEW_CONVERT_EXPR)
    new_arg0 = TREE_OPERAND (new_arg0, 0);

  if (TREE_CODE (arg1) == SSA_NAME)
    {
      /* Check if arg1 is an SSA_NAME and the stmt which defines arg1
	 is a conversion.  */
      arg1_def_stmt = SSA_NAME_DEF_STMT (arg1);
      if (!is_gimple_assign (arg1_def_stmt)
	  || gimple_assign_rhs_code (arg1_def_stmt) != convert_code)
	return false;

      /* Use the RHS as new_arg1.  */
      new_arg1 = gimple_assign_rhs1 (arg1_def_stmt);
      if (convert_code == VIEW_CONVERT_EXPR)
	new_arg1 = TREE_OPERAND (new_arg1, 0);
    }
  else
    {
      /* If arg1 is an INTEGER_CST, fold it to new type.  */
      if (INTEGRAL_TYPE_P (TREE_TYPE (new_arg0))
	  && int_fits_type_p (arg1, TREE_TYPE (new_arg0)))
	{
	  if (gimple_assign_cast_p (arg0_def_stmt))
	    new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1);
	  else
	    return false;
	}
      else
	return false;
    }

  /*  If arg0/arg1 have > 1 use, then this transformation actually increases
      the number of expressions evaluated at runtime.  */
  if (!has_single_use (arg0)
      || (arg1_def_stmt && !has_single_use (arg1)))
    return false;

  /* If types of new_arg0 and new_arg1 are different bailout.  */
  if (!types_compatible_p (TREE_TYPE (new_arg0), TREE_TYPE (new_arg1)))
    return false;

  /* Create a new PHI stmt.  */
  result = PHI_RESULT (phi);
  temp = make_ssa_name (TREE_TYPE (new_arg0), NULL);
  newphi = create_phi_node (temp, gimple_bb (phi));

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "PHI ");
      print_generic_expr (dump_file, gimple_phi_result (phi), 0);
      fprintf (dump_file,
	       " changed to factor conversion out from COND_EXPR.\n");
      fprintf (dump_file, "New stmt with CAST that defines ");
      print_generic_expr (dump_file, result, 0);
      fprintf (dump_file, ".\n");
    }

  /* Remove the old cast(s) that has single use.  */
  gsi_for_def = gsi_for_stmt (arg0_def_stmt);
  gsi_remove (&gsi_for_def, true);
  if (arg1_def_stmt)
    {
      gsi_for_def = gsi_for_s