void gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p, tree *lhs_p, tree *rhs_p) { gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison || TREE_CODE (cond) == TRUTH_NOT_EXPR || is_gimple_min_invariant (cond) || SSA_VAR_P (cond)); extract_ops_from_tree (cond, code_p, lhs_p, rhs_p); /* Canonicalize conditionals of the form 'if (!VAL)'. */ if (*code_p == TRUTH_NOT_EXPR) { *code_p = EQ_EXPR; gcc_assert (*lhs_p && *rhs_p == NULL_TREE); *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); } /* Canonicalize conditionals of the form 'if (VAL)' */ else if (TREE_CODE_CLASS (*code_p) != tcc_comparison) { *code_p = NE_EXPR; gcc_assert (*lhs_p && *rhs_p == NULL_TREE); *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); } }
tree gimple_simplify (enum tree_code code, tree type, tree op0, tree op1, gimple_seq *seq, tree (*valueize)(tree)) { if (constant_for_folding (op0) && constant_for_folding (op1)) { tree res = const_binop (code, type, op0, op1); if (res != NULL_TREE && CONSTANT_CLASS_P (res)) return res; } /* Canonicalize operand order both for matching and fallback stmt generation. */ if ((commutative_tree_code (code) || TREE_CODE_CLASS (code) == tcc_comparison) && tree_swap_operands_p (op0, op1, false)) { tree tem = op0; op0 = op1; op1 = tem; if (TREE_CODE_CLASS (code) == tcc_comparison) code = swap_tree_comparison (code); } code_helper rcode; tree ops[3] = {}; if (!gimple_simplify (&rcode, ops, seq, valueize, code, type, op0, op1)) return NULL_TREE; return maybe_push_res_to_seq (rcode, type, ops, seq); }
bool gimple_resimplify2 (gimple_seq *seq, code_helper *res_code, tree type, tree *res_ops, tree (*valueize)(tree)) { if (constant_for_folding (res_ops[0]) && constant_for_folding (res_ops[1])) { tree tem = NULL_TREE; if (res_code->is_tree_code ()) tem = const_binop (*res_code, type, res_ops[0], res_ops[1]); else tem = fold_const_call (combined_fn (*res_code), type, res_ops[0], res_ops[1]); if (tem != NULL_TREE && CONSTANT_CLASS_P (tem)) { if (TREE_OVERFLOW_P (tem)) tem = drop_tree_overflow (tem); res_ops[0] = tem; res_ops[1] = NULL_TREE; res_ops[2] = NULL_TREE; *res_code = TREE_CODE (res_ops[0]); return true; } } /* Canonicalize operand order. */ bool canonicalized = false; if (res_code->is_tree_code () && (TREE_CODE_CLASS ((enum tree_code) *res_code) == tcc_comparison || commutative_tree_code (*res_code)) && tree_swap_operands_p (res_ops[0], res_ops[1])) { std::swap (res_ops[0], res_ops[1]); if (TREE_CODE_CLASS ((enum tree_code) *res_code) == tcc_comparison) *res_code = swap_tree_comparison (*res_code); canonicalized = true; } code_helper res_code2; tree res_ops2[3] = {}; if (gimple_simplify (&res_code2, res_ops2, seq, valueize, *res_code, type, res_ops[0], res_ops[1])) { *res_code = res_code2; res_ops[0] = res_ops2[0]; res_ops[1] = res_ops2[1]; res_ops[2] = res_ops2[2]; return true; } return canonicalized; }
/* Check whether G is a potential conditional compare candidate. */ static bool ccmp_candidate_p (gimple *g) { tree rhs = gimple_assign_rhs_to_tree (g); tree lhs, op0, op1; gimple *gs0, *gs1; enum tree_code tcode, tcode0, tcode1; tcode = TREE_CODE (rhs); if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR) return false; lhs = gimple_assign_lhs (g); op0 = TREE_OPERAND (rhs, 0); op1 = TREE_OPERAND (rhs, 1); if ((TREE_CODE (op0) != SSA_NAME) || (TREE_CODE (op1) != SSA_NAME) || !has_single_use (lhs)) return false; gs0 = get_gimple_for_ssa_name (op0); gs1 = get_gimple_for_ssa_name (op1); if (!gs0 || !gs1 || !is_gimple_assign (gs0) || !is_gimple_assign (gs1) /* g, gs0 and gs1 must be in the same basic block, since current stage is out-of-ssa. We can not guarantee the correctness when forwording the gs0 and gs1 into g whithout DATAFLOW analysis. */ || gimple_bb (gs0) != gimple_bb (gs1) || gimple_bb (gs0) != gimple_bb (g)) return false; if (!(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0))) || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0)))) || !(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))) || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))))) return false; tcode0 = gimple_assign_rhs_code (gs0); tcode1 = gimple_assign_rhs_code (gs1); if (TREE_CODE_CLASS (tcode0) == tcc_comparison && TREE_CODE_CLASS (tcode1) == tcc_comparison) return true; if (TREE_CODE_CLASS (tcode0) == tcc_comparison && ccmp_candidate_p (gs1)) return true; else if (TREE_CODE_CLASS (tcode1) == tcc_comparison && ccmp_candidate_p (gs0)) return true; /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since there is no way to set the CC flag. */ return false; }
static struct loop * outermost_invariant_loop_expr (tree expr, struct loop *loop) { enum tree_code_class codeclass = TREE_CODE_CLASS (TREE_CODE (expr)); unsigned i, nops; struct loop *max_loop = superloop_at_depth (loop, 1), *aloop; if (TREE_CODE (expr) == SSA_NAME || TREE_CODE (expr) == INTEGER_CST || is_gimple_min_invariant (expr)) return outermost_invariant_loop (expr, loop); if (codeclass != tcc_unary && codeclass != tcc_binary && codeclass != tcc_expression && codeclass != tcc_vl_exp && codeclass != tcc_comparison) return NULL; nops = TREE_OPERAND_LENGTH (expr); for (i = 0; i < nops; i++) { aloop = outermost_invariant_loop_expr (TREE_OPERAND (expr, i), loop); if (!aloop) return NULL; if (flow_loop_nested_p (max_loop, aloop)) max_loop = aloop; } return max_loop; }
static tree get_string_cst(tree var) { if (var == NULL_TREE) return NULL_TREE; if (TREE_CODE(var) == STRING_CST) return var; switch (TREE_CODE_CLASS(TREE_CODE(var))) { case tcc_expression: case tcc_reference: { int i; for (i = 0; i < TREE_OPERAND_LENGTH(var); i++) { tree ret = get_string_cst(TREE_OPERAND(var, i)); if (ret != NULL_TREE) return ret; } break; } default: break; } return NULL_TREE; }
/* Langhook for tree_size: determine size of our 'x' and 'c' nodes. */ size_t cp_tree_size (enum tree_code code) { gcc_checking_assert (code >= NUM_TREE_CODES); switch (code) { case PTRMEM_CST: return sizeof (ptrmem_cst); case BASELINK: return sizeof (tree_baselink); case TEMPLATE_PARM_INDEX: return sizeof (template_parm_index); case DEFAULT_ARG: return sizeof (tree_default_arg); case DEFERRED_NOEXCEPT: return sizeof (tree_deferred_noexcept); case OVERLOAD: return sizeof (tree_overload); case STATIC_ASSERT: return sizeof (tree_static_assert); case TYPE_ARGUMENT_PACK: case TYPE_PACK_EXPANSION: return sizeof (tree_type_non_common); case NONTYPE_ARGUMENT_PACK: case EXPR_PACK_EXPANSION: return sizeof (tree_exp); case ARGUMENT_PACK_SELECT: return sizeof (tree_argument_pack_select); case TRAIT_EXPR: return sizeof (tree_trait_expr); case LAMBDA_EXPR: return sizeof (tree_lambda_expr); case TEMPLATE_INFO: return sizeof (tree_template_info); case CONSTRAINT_INFO: return sizeof (tree_constraint_info); case USERDEF_LITERAL: return sizeof (tree_userdef_literal); case TEMPLATE_DECL: return sizeof (tree_template_decl); default: switch (TREE_CODE_CLASS (code)) { case tcc_declaration: return sizeof (tree_decl_non_common); case tcc_type: return sizeof (tree_type_non_common); default: gcc_unreachable (); } } /* NOTREACHED */ }
static tree get_expr_type (enum tree_code code, tree op) { return (TREE_CODE_CLASS (code) == tcc_comparison) ? boolean_type_node : TREE_TYPE (op); }
/* Given the jump function JFUNC, compute the lattice LAT that describes the value coming down the callsite. INFO describes the caller node so that pass-through jump functions can be evaluated. */ static void ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat, struct ipa_jump_func *jfunc) { if (jfunc->type == IPA_JF_CONST) { lat->type = IPA_CONST_VALUE; lat->constant = jfunc->value.constant; } else if (jfunc->type == IPA_JF_PASS_THROUGH) { struct ipcp_lattice *caller_lat; tree cst; caller_lat = ipcp_get_lattice (info, jfunc->value.pass_through.formal_id); lat->type = caller_lat->type; if (caller_lat->type != IPA_CONST_VALUE) return; cst = caller_lat->constant; if (jfunc->value.pass_through.operation != NOP_EXPR) { tree restype; if (TREE_CODE_CLASS (jfunc->value.pass_through.operation) == tcc_comparison) restype = boolean_type_node; else restype = TREE_TYPE (cst); cst = fold_binary (jfunc->value.pass_through.operation, restype, cst, jfunc->value.pass_through.operand); } if (!cst || !is_gimple_ip_invariant (cst)) lat->type = IPA_BOTTOM; lat->constant = cst; } else if (jfunc->type == IPA_JF_ANCESTOR) { struct ipcp_lattice *caller_lat; tree t; caller_lat = ipcp_get_lattice (info, jfunc->value.ancestor.formal_id); lat->type = caller_lat->type; if (caller_lat->type != IPA_CONST_VALUE) return; if (TREE_CODE (caller_lat->constant) != ADDR_EXPR) { /* This can happen when the constant is a NULL pointer. */ lat->type = IPA_BOTTOM; return; } t = TREE_OPERAND (caller_lat->constant, 0); t = build_ref_for_offset (EXPR_LOCATION (t), t, jfunc->value.ancestor.offset, jfunc->value.ancestor.type, NULL, false); lat->constant = build_fold_addr_expr (t); } else lat->type = IPA_BOTTOM; }
static void set_based_decl_codes(const_tree type, struct decl_hash *decl_hash_data) { gcc_assert(type != NULL_TREE); gcc_assert(TREE_CODE_CLASS(TREE_CODE(type)) == tcc_type); while (type && decl_hash_data->tree_codes_len < CODES_LIMIT) { decl_hash_data->tree_codes[decl_hash_data->tree_codes_len] = get_tree_code(type); decl_hash_data->tree_codes_len++; type = TREE_TYPE(type); } }
static bool can_propagate_from (gimple def_stmt) { use_operand_p use_p; ssa_op_iter iter; gcc_assert (is_gimple_assign (def_stmt)); /* If the rhs has side-effects we cannot propagate from it. */ if (gimple_has_volatile_ops (def_stmt)) return false; /* If the rhs is a load we cannot propagate from it. */ if (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)) == tcc_reference || TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)) == tcc_declaration) return false; /* Constants can be always propagated. */ if (gimple_assign_single_p (def_stmt) && is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt))) return true; /* We cannot propagate ssa names that occur in abnormal phi nodes. */ FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_USE) if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (USE_FROM_PTR (use_p))) return false; /* If the definition is a conversion of a pointer to a function type, then we can not apply optimizations as some targets require function pointers to be canonicalized and in this case this optimization could eliminate a necessary canonicalization. */ if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt))) { tree rhs = gimple_assign_rhs1 (def_stmt); if (POINTER_TYPE_P (TREE_TYPE (rhs)) && TREE_CODE (TREE_TYPE (TREE_TYPE (rhs))) == FUNCTION_TYPE) return false; } return true; }
void recalculate_side_effects (tree t) { enum tree_code code = TREE_CODE (t); int len = TREE_CODE_LENGTH (code); int i; switch (TREE_CODE_CLASS (code)) { case tcc_expression: switch (code) { case INIT_EXPR: case MODIFY_EXPR: case VA_ARG_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: /* All of these have side-effects, no matter what their operands are. */ return; default: break; } /* Fall through. */ 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 */ TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t); for (i = 0; i < len; ++i) { 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 (); } }
static void build_and_record_new_cond (enum tree_code code, tree op0, tree op1, vec<cond_equivalence> *p, bool val = true) { cond_equivalence c; struct hashable_expr *cond = &c.cond; gcc_assert (TREE_CODE_CLASS (code) == tcc_comparison); cond->type = boolean_type_node; cond->kind = EXPR_BINARY; cond->ops.binary.op = code; cond->ops.binary.opnd0 = op0; cond->ops.binary.opnd1 = op1; c.value = val ? boolean_true_node : boolean_false_node; p->safe_push (c); }
static bool cilk_ignorable_spawn_rhs_op (tree exp) { enum tree_code code = TREE_CODE (exp); switch (TREE_CODE_CLASS (code)) { case tcc_expression: return code == ADDR_EXPR; case tcc_comparison: /* We need the spawn as operand 0 for now. That's where it appears in the only case we really care about, conversion to bool. */ return (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST); case tcc_unary: case tcc_reference: return true; default: return false; } }
bool is_gimple_formal_tmp_rhs (tree t) { enum tree_code code = TREE_CODE (t); switch (TREE_CODE_CLASS (code)) { case tcc_unary: case tcc_binary: case tcc_comparison: return true; default: break; } switch (code) { case TRUTH_NOT_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case TRUTH_XOR_EXPR: case ADDR_EXPR: case CALL_EXPR: case CONSTRUCTOR: case COMPLEX_EXPR: case INTEGER_CST: case REAL_CST: case STRING_CST: case COMPLEX_CST: case VECTOR_CST: case OBJ_TYPE_REF: case ASSERT_EXPR: return true; default: break; } return is_gimple_lvalue (t) || is_gimple_val (t); }
tree build_stmt (location_t loc, enum tree_code code, ...) { tree ret; int length, i; va_list p; bool side_effects; /* This function cannot be used to construct variably-sized nodes. */ gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp); va_start (p, code); ret = make_node (code); TREE_TYPE (ret) = void_type_node; length = TREE_CODE_LENGTH (code); SET_EXPR_LOCATION (ret, loc); /* TREE_SIDE_EFFECTS will already be set for statements with implicit side effects. Here we make sure it is set for other expressions by checking whether the parameters have side effects. */ side_effects = false; for (i = 0; i < length; i++) { tree t = va_arg (p, tree); if (t && !TYPE_P (t)) side_effects |= TREE_SIDE_EFFECTS (t); TREE_OPERAND (ret, i) = t; } TREE_SIDE_EFFECTS (ret) |= side_effects; va_end (p); return ret; }
static tree combine_cond_expr_cond (enum tree_code code, tree type, tree op0, tree op1, bool invariant_only) { tree t; gcc_assert (TREE_CODE_CLASS (code) == tcc_comparison); t = fold_binary (code, type, op0, op1); if (!t) return NULL_TREE; /* Require that we got a boolean type out if we put one in. */ gcc_assert (TREE_CODE (TREE_TYPE (t)) == TREE_CODE (type)); /* Canonicalize the combined condition for use in a COND_EXPR. */ t = canonicalize_cond_expr_cond (t); /* Bail out if we required an invariant but didn't get one. */ if (!t || (invariant_only && !is_gimple_min_invariant (t))) return NULL_TREE; return t; }
static bool ifcombine_iforif (basic_block inner_cond_bb, basic_block outer_cond_bb) { gimple inner_cond, outer_cond; tree name1, name2, bits1, bits2; inner_cond = last_stmt (inner_cond_bb); if (!inner_cond || gimple_code (inner_cond) != GIMPLE_COND) return false; outer_cond = last_stmt (outer_cond_bb); if (!outer_cond || gimple_code (outer_cond) != GIMPLE_COND) return false; /* See if we have two bit tests of the same name in both tests. In that case remove the outer test and change the inner one to test for name & (bits1 | bits2) != 0. */ if (recognize_bits_test (inner_cond, &name1, &bits1) && recognize_bits_test (outer_cond, &name2, &bits2)) { gimple_stmt_iterator gsi; tree t; /* Find the common name which is bit-tested. */ if (name1 == name2) ; else if (bits1 == bits2) { t = name2; name2 = bits2; bits2 = t; t = name1; name1 = bits1; bits1 = t; } else if (name1 == bits2) { t = name2; name2 = bits2; bits2 = t; } else if (bits1 == name2) { t = name1; name1 = bits1; bits1 = t; } else return false; /* As we strip non-widening conversions in finding a common name that is tested make sure to end up with an integral type for building the bit operations. */ if (TYPE_PRECISION (TREE_TYPE (bits1)) >= TYPE_PRECISION (TREE_TYPE (bits2))) { bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1); name1 = fold_convert (TREE_TYPE (bits1), name1); bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2); bits2 = fold_convert (TREE_TYPE (bits1), bits2); } else { bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2); name1 = fold_convert (TREE_TYPE (bits2), name1); bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1); bits1 = fold_convert (TREE_TYPE (bits2), bits1); } /* Do it. */ gsi = gsi_for_stmt (inner_cond); t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), bits1, bits2); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); t = fold_build2 (NE_EXPR, boolean_type_node, t, build_int_cst (TREE_TYPE (t), 0)); gimple_cond_set_condition_from_tree (inner_cond, t); update_stmt (inner_cond); /* Leave CFG optimization to cfg_cleanup. */ gimple_cond_set_condition_from_tree (outer_cond, boolean_false_node); update_stmt (outer_cond); if (dump_file) { fprintf (dump_file, "optimizing bits or bits test to "); print_generic_expr (dump_file, name1, 0); fprintf (dump_file, " & T != 0\nwith temporary T = "); print_generic_expr (dump_file, bits1, 0); fprintf (dump_file, " | "); print_generic_expr (dump_file, bits2, 0); fprintf (dump_file, "\n"); } return true; } /* See if we have two comparisons that we can merge into one. This happens for C++ operator overloading where for example GE_EXPR is implemented as GT_EXPR || EQ_EXPR. */ else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison && operand_equal_p (gimple_cond_lhs (inner_cond), gimple_cond_lhs (outer_cond), 0) && operand_equal_p (gimple_cond_rhs (inner_cond), gimple_cond_rhs (outer_cond), 0)) { enum tree_code code1 = gimple_cond_code (inner_cond); enum tree_code code2 = gimple_cond_code (outer_cond); enum tree_code code; tree t; #define CHK(a,b) ((code1 == a ## _EXPR && code2 == b ## _EXPR) \ || (code2 == a ## _EXPR && code1 == b ## _EXPR)) /* Merge the two condition codes if possible. */ if (code1 == code2) code = code1; else if (CHK (EQ, LT)) code = LE_EXPR; else if (CHK (EQ, GT)) code = GE_EXPR; else if (CHK (LT, LE)) code = LE_EXPR; else if (CHK (GT, GE)) code = GE_EXPR; else if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (inner_cond))) || flag_unsafe_math_optimizations) { if (CHK (LT, GT)) code = NE_EXPR; else if (CHK (LT, NE)) code = NE_EXPR; else if (CHK (GT, NE)) code = NE_EXPR; else return false; } /* We could check for combinations leading to trivial true/false. */ else return false; #undef CHK /* Do it. */ t = fold_build2 (code, boolean_type_node, gimple_cond_lhs (outer_cond), gimple_cond_rhs (outer_cond)); t = canonicalize_cond_expr_cond (t); if (!t) return false; gimple_cond_set_condition_from_tree (inner_cond, t); update_stmt (inner_cond); /* Leave CFG optimization to cfg_cleanup. */ gimple_cond_set_condition_from_tree (outer_cond, boolean_false_node); update_stmt (outer_cond); if (dump_file) { fprintf (dump_file, "optimizing two comparisons to "); print_generic_expr (dump_file, t, 0); fprintf (dump_file, "\n"); } return true; } return false; }
static int forward_propagate_into_gimple_cond (gimple stmt) { int did_something = 0; do { tree tmp = NULL_TREE; tree name, rhs0 = NULL_TREE, rhs1 = NULL_TREE; gimple def_stmt; bool single_use0_p = false, single_use1_p = false; enum tree_code code = gimple_cond_code (stmt); /* We can do tree combining on SSA_NAME and comparison expressions. */ if (TREE_CODE_CLASS (gimple_cond_code (stmt)) == tcc_comparison && TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME) { /* For comparisons use the first operand, that is likely to simplify comparisons against constants. */ name = gimple_cond_lhs (stmt); def_stmt = get_prop_source_stmt (name, false, &single_use0_p); if (def_stmt && can_propagate_from (def_stmt)) { tree op1 = gimple_cond_rhs (stmt); rhs0 = rhs_to_tree (TREE_TYPE (op1), def_stmt); tmp = combine_cond_expr_cond (code, boolean_type_node, rhs0, op1, !single_use0_p); } /* If that wasn't successful, try the second operand. */ if (tmp == NULL_TREE && TREE_CODE (gimple_cond_rhs (stmt)) == SSA_NAME) { tree op0 = gimple_cond_lhs (stmt); name = gimple_cond_rhs (stmt); def_stmt = get_prop_source_stmt (name, false, &single_use1_p); if (!def_stmt || !can_propagate_from (def_stmt)) return did_something; rhs1 = rhs_to_tree (TREE_TYPE (op0), def_stmt); tmp = combine_cond_expr_cond (code, boolean_type_node, op0, rhs1, !single_use1_p); } /* If that wasn't successful either, try both operands. */ if (tmp == NULL_TREE && rhs0 != NULL_TREE && rhs1 != NULL_TREE) tmp = combine_cond_expr_cond (code, boolean_type_node, rhs0, fold_convert (TREE_TYPE (rhs0), rhs1), !(single_use0_p && single_use1_p)); } if (tmp) { if (dump_file && tmp) { tree cond = build2 (gimple_cond_code (stmt), boolean_type_node, gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); fprintf (dump_file, " Replaced '"); print_generic_expr (dump_file, cond, 0); fprintf (dump_file, "' with '"); print_generic_expr (dump_file, tmp, 0); fprintf (dump_file, "'\n"); } gimple_cond_set_condition_from_tree (stmt, unshare_expr (tmp)); update_stmt (stmt); /* Remove defining statements. */ remove_prop_source_from_use (name, NULL); if (is_gimple_min_invariant (tmp)) did_something = 2; else if (did_something == 0) did_something = 1; /* Continue combining. */ continue; } break; } while (1); return did_something; }
bool gimple_simplify (gimple *stmt, code_helper *rcode, tree *ops, gimple_seq *seq, tree (*valueize)(tree), tree (*top_valueize)(tree)) { switch (gimple_code (stmt)) { case GIMPLE_ASSIGN: { enum tree_code code = gimple_assign_rhs_code (stmt); tree type = TREE_TYPE (gimple_assign_lhs (stmt)); switch (gimple_assign_rhs_class (stmt)) { case GIMPLE_SINGLE_RHS: if (code == REALPART_EXPR || code == IMAGPART_EXPR || code == VIEW_CONVERT_EXPR) { tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); bool valueized = false; op0 = do_valueize (op0, top_valueize, valueized); *rcode = code; ops[0] = op0; return (gimple_resimplify1 (seq, rcode, type, ops, valueize) || valueized); } else if (code == BIT_FIELD_REF) { tree rhs1 = gimple_assign_rhs1 (stmt); tree op0 = TREE_OPERAND (rhs1, 0); bool valueized = false; op0 = do_valueize (op0, top_valueize, valueized); *rcode = code; ops[0] = op0; ops[1] = TREE_OPERAND (rhs1, 1); ops[2] = TREE_OPERAND (rhs1, 2); return (gimple_resimplify3 (seq, rcode, type, ops, valueize) || valueized); } else if (code == SSA_NAME && top_valueize) { tree op0 = gimple_assign_rhs1 (stmt); tree valueized = top_valueize (op0); if (!valueized || op0 == valueized) return false; ops[0] = valueized; *rcode = TREE_CODE (op0); return true; } break; case GIMPLE_UNARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); bool valueized = false; rhs1 = do_valueize (rhs1, top_valueize, valueized); *rcode = code; ops[0] = rhs1; return (gimple_resimplify1 (seq, rcode, type, ops, valueize) || valueized); } case GIMPLE_BINARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); tree rhs2 = gimple_assign_rhs2 (stmt); bool valueized = false; rhs1 = do_valueize (rhs1, top_valueize, valueized); rhs2 = do_valueize (rhs2, top_valueize, valueized); *rcode = code; ops[0] = rhs1; ops[1] = rhs2; return (gimple_resimplify2 (seq, rcode, type, ops, valueize) || valueized); } case GIMPLE_TERNARY_RHS: { bool valueized = false; tree rhs1 = gimple_assign_rhs1 (stmt); /* If this is a [VEC_]COND_EXPR first try to simplify an embedded GENERIC condition. */ if (code == COND_EXPR || code == VEC_COND_EXPR) { if (COMPARISON_CLASS_P (rhs1)) { tree lhs = TREE_OPERAND (rhs1, 0); tree rhs = TREE_OPERAND (rhs1, 1); lhs = do_valueize (lhs, top_valueize, valueized); rhs = do_valueize (rhs, top_valueize, valueized); code_helper rcode2 = TREE_CODE (rhs1); tree ops2[3] = {}; ops2[0] = lhs; ops2[1] = rhs; if ((gimple_resimplify2 (seq, &rcode2, TREE_TYPE (rhs1), ops2, valueize) || valueized) && rcode2.is_tree_code ()) { valueized = true; if (TREE_CODE_CLASS ((enum tree_code)rcode2) == tcc_comparison) rhs1 = build2 (rcode2, TREE_TYPE (rhs1), ops2[0], ops2[1]); else if (rcode2 == SSA_NAME || rcode2 == INTEGER_CST) rhs1 = ops2[0]; else valueized = false; } } } tree rhs2 = gimple_assign_rhs2 (stmt); tree rhs3 = gimple_assign_rhs3 (stmt); rhs1 = do_valueize (rhs1, top_valueize, valueized); rhs2 = do_valueize (rhs2, top_valueize, valueized); rhs3 = do_valueize (rhs3, top_valueize, valueized); *rcode = code; ops[0] = rhs1; ops[1] = rhs2; ops[2] = rhs3; return (gimple_resimplify3 (seq, rcode, type, ops, valueize) || valueized); } default: gcc_unreachable (); } break; } case GIMPLE_CALL: /* ??? This way we can't simplify calls with side-effects. */ if (gimple_call_lhs (stmt) != NULL_TREE && gimple_call_num_args (stmt) >= 1 && gimple_call_num_args (stmt) <= 3) { tree fn = gimple_call_fn (stmt); /* ??? Internal function support missing. */ if (!fn) return false; bool valueized = false; fn = do_valueize (fn, top_valueize, valueized); if (TREE_CODE (fn) != ADDR_EXPR || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL) return false; tree decl = TREE_OPERAND (fn, 0); if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL || !builtin_decl_implicit (DECL_FUNCTION_CODE (decl)) || !gimple_builtin_call_types_compatible_p (stmt, decl)) return false; tree type = TREE_TYPE (gimple_call_lhs (stmt)); *rcode = DECL_FUNCTION_CODE (decl); for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i) { tree arg = gimple_call_arg (stmt, i); ops[i] = do_valueize (arg, top_valueize, valueized); } switch (gimple_call_num_args (stmt)) { case 1: return (gimple_resimplify1 (seq, rcode, type, ops, valueize) || valueized); case 2: return (gimple_resimplify2 (seq, rcode, type, ops, valueize) || valueized); case 3: return (gimple_resimplify3 (seq, rcode, type, ops, valueize) || valueized); default: gcc_unreachable (); } } break; case GIMPLE_COND: { tree lhs = gimple_cond_lhs (stmt); tree rhs = gimple_cond_rhs (stmt); bool valueized = false; lhs = do_valueize (lhs, top_valueize, valueized); rhs = do_valueize (rhs, top_valueize, valueized); *rcode = gimple_cond_code (stmt); ops[0] = lhs; ops[1] = rhs; return (gimple_resimplify2 (seq, rcode, boolean_type_node, ops, valueize) || valueized); } default: break; } return false; }
void print_node (FILE *file, const char *prefix, tree node, int indent) { int hash; struct bucket *b; machine_mode mode; enum tree_code_class tclass; int len; int i; expanded_location xloc; enum tree_code code; if (node == 0) return; code = TREE_CODE (node); tclass = TREE_CODE_CLASS (code); /* Don't get too deep in nesting. If the user wants to see deeper, it is easy to use the address of a lowest-level node as an argument in another call to debug_tree. */ if (indent > 24) { print_node_brief (file, prefix, node, indent); return; } if (indent > 8 && (tclass == tcc_type || tclass == tcc_declaration)) { print_node_brief (file, prefix, node, indent); return; } /* It is unsafe to look at any other fields of an ERROR_MARK node. */ if (code == ERROR_MARK) { print_node_brief (file, prefix, node, indent); return; } /* Allow this function to be called if the table is not there. */ if (table) { hash = ((uintptr_t) node) % HASH_SIZE; /* If node is in the table, just mention its address. */ for (b = table[hash]; b; b = b->next) if (b->node == node) { print_node_brief (file, prefix, node, indent); return; } /* Add this node to the table. */ b = XNEW (struct bucket); b->node = node; b->next = table[hash]; table[hash] = b; } /* Indent to the specified column, since this is the long form. */ indent_to (file, indent); /* Print the slot this node is in, and its code, and address. */ fprintf (file, "%s <%s", prefix, get_tree_code_name (code)); dump_addr (file, " ", node); /* Print the name, if any. */ if (tclass == tcc_declaration) { if (DECL_NAME (node)) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); else if (code == LABEL_DECL && LABEL_DECL_UID (node) != -1) { if (dump_flags & TDF_NOUID) fprintf (file, " L.xxxx"); else fprintf (file, " L.%d", (int) LABEL_DECL_UID (node)); } else { if (dump_flags & TDF_NOUID) fprintf (file, " %c.xxxx", code == CONST_DECL ? 'C' : 'D'); else fprintf (file, " %c.%u", code == CONST_DECL ? 'C' : 'D', DECL_UID (node)); } } else if (tclass == tcc_type) { if (TYPE_NAME (node)) { if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node))); else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL && DECL_NAME (TYPE_NAME (node))) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)))); } } if (code == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (node)); if (code == INTEGER_CST) { if (indent <= 4) print_node_brief (file, "type", TREE_TYPE (node), indent + 4); } else if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) { print_node (file, "type", TREE_TYPE (node), indent + 4); if (TREE_TYPE (node)) indent_to (file, indent + 3); } if (!TYPE_P (node) && TREE_SIDE_EFFECTS (node)) fputs (" side-effects", file); if (TYPE_P (node) ? TYPE_READONLY (node) : TREE_READONLY (node)) fputs (" readonly", file); if (TYPE_P (node) && TYPE_ATOMIC (node)) fputs (" atomic", file); if (!TYPE_P (node) && TREE_CONSTANT (node)) fputs (" constant", file); else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node)) fputs (" sizes-gimplified", file); if (TYPE_P (node) && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); if (TREE_ADDRESSABLE (node)) fputs (" addressable", file); if (TREE_THIS_VOLATILE (node)) fputs (" volatile", file); if (TREE_ASM_WRITTEN (node)) fputs (" asm_written", file); if (TREE_USED (node)) fputs (" used", file); if (TREE_NOTHROW (node)) fputs (" nothrow", file); if (TREE_PUBLIC (node)) fputs (" public", file); if (TREE_PRIVATE (node)) fputs (" private", file); if (TREE_PROTECTED (node)) fputs (" protected", file); if (TREE_STATIC (node)) fputs (code == CALL_EXPR ? " must-tail-call" : " static", file); if (TREE_DEPRECATED (node)) fputs (" deprecated", file); if (TREE_VISITED (node)) fputs (" visited", file); if (code != TREE_VEC && code != INTEGER_CST && code != SSA_NAME) { if (TREE_LANG_FLAG_0 (node)) fputs (" tree_0", file); if (TREE_LANG_FLAG_1 (node)) fputs (" tree_1", file); if (TREE_LANG_FLAG_2 (node)) fputs (" tree_2", file); if (TREE_LANG_FLAG_3 (node)) fputs (" tree_3", file); if (TREE_LANG_FLAG_4 (node)) fputs (" tree_4", file); if (TREE_LANG_FLAG_5 (node)) fputs (" tree_5", file); if (TREE_LANG_FLAG_6 (node)) fputs (" tree_6", file); } /* DECL_ nodes have additional attributes. */ switch (TREE_CODE_CLASS (code)) { case tcc_declaration: if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_UNSIGNED (node)) fputs (" unsigned", file); if (DECL_IGNORED_P (node)) fputs (" ignored", file); if (DECL_ABSTRACT_P (node)) fputs (" abstract", file); if (DECL_EXTERNAL (node)) fputs (" external", file); if (DECL_NONLOCAL (node)) fputs (" nonlocal", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) { if (DECL_WEAK (node)) fputs (" weak", file); if (DECL_IN_SYSTEM_HEADER (node)) fputs (" in_system_header", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL) && code != LABEL_DECL && code != FUNCTION_DECL && DECL_REGISTER (node)) fputs (" regdecl", file); if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node)) fputs (" suppress-debug", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_TARGET (node)) fputs (" function-specific-target", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (node)) fputs (" function-specific-opt", file); if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (node)) fputs (" autoinline", file); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) fputs (" built-in", file); if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node)) fputs (" static-chain", file); if (TREE_CODE (node) == FUNCTION_DECL && decl_is_tm_clone (node)) fputs (" tm-clone", file); if (code == FIELD_DECL && DECL_PACKED (node)) fputs (" packed", file); if (code == FIELD_DECL && DECL_BIT_FIELD (node)) fputs (" bit-field", file); if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (node)) fputs (" nonaddressable", file); if (code == LABEL_DECL && EH_LANDING_PAD_NR (node)) fprintf (file, " landing-pad:%d", EH_LANDING_PAD_NR (node)); if (code == VAR_DECL && DECL_IN_TEXT_SECTION (node)) fputs (" in-text-section", file); if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (node)) fputs (" in-constant-pool", file); if (code == VAR_DECL && DECL_COMMON (node)) fputs (" common", file); if (code == VAR_DECL && DECL_THREAD_LOCAL_P (node)) { fputs (" ", file); fputs (tls_model_names[DECL_TLS_MODEL (node)], file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_VIRTUAL_P (node)) fputs (" virtual", file); if (DECL_PRESERVE_P (node)) fputs (" preserve", file); if (DECL_LANG_FLAG_0 (node)) fputs (" decl_0", file); if (DECL_LANG_FLAG_1 (node)) fputs (" decl_1", file); if (DECL_LANG_FLAG_2 (node)) fputs (" decl_2", file); if (DECL_LANG_FLAG_3 (node)) fputs (" decl_3", file); if (DECL_LANG_FLAG_4 (node)) fputs (" decl_4", file); if (DECL_LANG_FLAG_5 (node)) fputs (" decl_5", file); if (DECL_LANG_FLAG_6 (node)) fputs (" decl_6", file); if (DECL_LANG_FLAG_7 (node)) fputs (" decl_7", file); mode = DECL_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); } if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL) && DECL_BY_REFERENCE (node)) fputs (" passed-by-reference", file); if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS) && DECL_DEFER_OUTPUT (node)) fputs (" defer-output", file); xloc = expand_location (DECL_SOURCE_LOCATION (node)); fprintf (file, " file %s line %d col %d", xloc.file, xloc.line, xloc.column); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node (file, "size", DECL_SIZE (node), indent + 4); print_node (file, "unit size", DECL_SIZE_UNIT (node), indent + 4); if (code != FUNCTION_DECL || DECL_BUILT_IN (node)) indent_to (file, indent + 3); if (DECL_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d", DECL_ALIGN (node)); if (code == FIELD_DECL) fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, DECL_OFFSET_ALIGN (node)); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) { if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD) fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node)); else fprintf (file, " built-in %s:%s", built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)], built_in_names[(int) DECL_FUNCTION_CODE (node)]); } } if (code == FIELD_DECL) { print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4); print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node), indent + 4); if (DECL_BIT_FIELD_TYPE (node)) print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node), indent + 4); } print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node_brief (file, "attributes", DECL_ATTRIBUTES (node), indent + 4); if (code != PARM_DECL) print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) { print_node_brief (file, "abstract_origin", DECL_ABSTRACT_ORIGIN (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON)) { print_node (file, "result", DECL_RESULT_FLD (node), indent + 4); } lang_hooks.print_decl (file, node, indent); if (DECL_RTL_SET_P (node)) { indent_to (file, indent + 4); print_rtl (file, DECL_RTL (node)); } if (code == PARM_DECL) { print_node (file, "arg-type", DECL_ARG_TYPE (node), indent + 4); if (DECL_INCOMING_RTL (node) != 0) { indent_to (file, indent + 4); fprintf (file, "incoming-rtl "); print_rtl (file, DECL_INCOMING_RTL (node)); } } else if (code == FUNCTION_DECL && DECL_STRUCT_FUNCTION (node) != 0) { print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4); indent_to (file, indent + 4); dump_addr (file, "struct-function ", DECL_STRUCT_FUNCTION (node)); } if ((code == VAR_DECL || code == PARM_DECL) && DECL_HAS_VALUE_EXPR_P (node)) print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4); /* Print the decl chain only if decl is at second level. */ if (indent == 4) print_node (file, "chain", TREE_CHAIN (node), indent + 4); else print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_type: if (TYPE_UNSIGNED (node)) fputs (" unsigned", file); if (TYPE_NO_FORCE_BLK (node)) fputs (" no-force-blk", file); if (TYPE_STRING_FLAG (node)) fputs (" string-flag", file); if (TYPE_NEEDS_CONSTRUCTING (node)) fputs (" needs-constructing", file); if ((code == RECORD_TYPE || code == UNION_TYPE || code == QUAL_UNION_TYPE || code == ARRAY_TYPE) && TYPE_REVERSE_STORAGE_ORDER (node)) fputs (" reverse-storage-order", file); /* The transparent-union flag is used for different things in different nodes. */ if ((code == UNION_TYPE || code == RECORD_TYPE) && TYPE_TRANSPARENT_AGGR (node)) fputs (" transparent-aggr", file); else if (code == ARRAY_TYPE && TYPE_NONALIASED_COMPONENT (node)) fputs (" nonaliased-component", file); if (TYPE_PACKED (node)) fputs (" packed", file); if (TYPE_RESTRICT (node)) fputs (" restrict", file); if (TYPE_LANG_FLAG_0 (node)) fputs (" type_0", file); if (TYPE_LANG_FLAG_1 (node)) fputs (" type_1", file); if (TYPE_LANG_FLAG_2 (node)) fputs (" type_2", file); if (TYPE_LANG_FLAG_3 (node)) fputs (" type_3", file); if (TYPE_LANG_FLAG_4 (node)) fputs (" type_4", file); if (TYPE_LANG_FLAG_5 (node)) fputs (" type_5", file); if (TYPE_LANG_FLAG_6 (node)) fputs (" type_6", file); if (TYPE_LANG_FLAG_7 (node)) fputs (" type_7", file); mode = TYPE_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); print_node (file, "size", TYPE_SIZE (node), indent + 4); print_node (file, "unit size", TYPE_SIZE_UNIT (node), indent + 4); indent_to (file, indent + 3); if (TYPE_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d symtab %d alias set " HOST_WIDE_INT_PRINT_DEC, TYPE_ALIGN (node), TYPE_SYMTAB_ADDRESS (node), (HOST_WIDE_INT) TYPE_ALIAS_SET (node)); if (TYPE_STRUCTURAL_EQUALITY_P (node)) fprintf (file, " structural equality"); else dump_addr (file, " canonical type ", TYPE_CANONICAL (node)); print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4); if (INTEGRAL_TYPE_P (node) || code == REAL_TYPE || code == FIXED_POINT_TYPE) { fprintf (file, " precision %d", TYPE_PRECISION (node)); print_node_brief (file, "min", TYPE_MIN_VALUE (node), indent + 4); print_node_brief (file, "max", TYPE_MAX_VALUE (node), indent + 4); } if (code == ENUMERAL_TYPE) print_node (file, "values", TYPE_VALUES (node), indent + 4); else if (code == ARRAY_TYPE) print_node (file, "domain", TYPE_DOMAIN (node), indent + 4); else if (code == VECTOR_TYPE) fprintf (file, " nunits %d", (int) TYPE_VECTOR_SUBPARTS (node)); else if (code == RECORD_TYPE || code == UNION_TYPE || code == QUAL_UNION_TYPE) print_node (file, "fields", TYPE_FIELDS (node), indent + 4); else if (code == FUNCTION_TYPE || code == METHOD_TYPE) { if (TYPE_METHOD_BASETYPE (node)) print_node_brief (file, "method basetype", TYPE_METHOD_BASETYPE (node), indent + 4); print_node (file, "arg-types", TYPE_ARG_TYPES (node), indent + 4); } else if (code == OFFSET_TYPE) print_node_brief (file, "basetype", TYPE_OFFSET_BASETYPE (node), indent + 4); if (TYPE_CONTEXT (node)) print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4); lang_hooks.print_type (file, node, indent); if (TYPE_POINTER_TO (node) || TREE_CHAIN (node)) indent_to (file, indent + 3); print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node), indent + 4); print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node), indent + 4); print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_expression: case tcc_comparison: case tcc_unary: case tcc_binary: case tcc_reference: case tcc_statement: case tcc_vl_exp: if (code == BIND_EXPR) { print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4); print_node (file, "body", TREE_OPERAND (node, 1), indent + 4); print_node (file, "block", TREE_OPERAND (node, 2), indent + 4); break; } if (code == CALL_EXPR) { call_expr_arg_iterator iter; tree arg; print_node (file, "fn", CALL_EXPR_FN (node), indent + 4); print_node (file, "static_chain", CALL_EXPR_STATIC_CHAIN (node), indent + 4); i = 0; FOR_EACH_CALL_EXPR_ARG (arg, iter, node) { char temp[10]; sprintf (temp, "arg %d", i); print_node (file, temp, arg, indent + 4); i++; } }
/* Expand conditional compare gimple G. A typical CCMP sequence is like: CC0 = CMP (a, b); CC1 = CCMP (NE (CC0, 0), CMP (e, f)); ... CCn = CCMP (NE (CCn-1, 0), CMP (...)); hook gen_ccmp_first is used to expand the first compare. hook gen_ccmp_next is used to expand the following CCMP. PREP_SEQ returns all insns to prepare opearand. GEN_SEQ returns all compare insns. */ static rtx expand_ccmp_expr_1 (gimple *g, rtx *prep_seq, rtx *gen_seq) { tree exp = gimple_assign_rhs_to_tree (g); enum tree_code code = TREE_CODE (exp); gimple *gs0 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 0)); gimple *gs1 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 1)); rtx tmp; enum tree_code code0 = gimple_assign_rhs_code (gs0); enum tree_code code1 = gimple_assign_rhs_code (gs1); gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR); gcc_assert (gs0 && gs1 && is_gimple_assign (gs0) && is_gimple_assign (gs1)); if (TREE_CODE_CLASS (code0) == tcc_comparison) { if (TREE_CODE_CLASS (code1) == tcc_comparison) { int unsignedp0; enum rtx_code rcode0; unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0))); rcode0 = get_rtx_code (code0, unsignedp0); tmp = targetm.gen_ccmp_first (prep_seq, gen_seq, rcode0, gimple_assign_rhs1 (gs0), gimple_assign_rhs2 (gs0)); if (!tmp) return NULL_RTX; return expand_ccmp_next (gs1, code, tmp, prep_seq, gen_seq); } else { tmp = expand_ccmp_expr_1 (gs1, prep_seq, gen_seq); if (!tmp) return NULL_RTX; return expand_ccmp_next (gs0, code, tmp, prep_seq, gen_seq); } } else { gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR); if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) == tcc_comparison) { tmp = expand_ccmp_expr_1 (gs0, prep_seq, gen_seq); if (!tmp) return NULL_RTX; return expand_ccmp_next (gs1, code, tmp, prep_seq, gen_seq); } else { gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR); } } return NULL_RTX; }
static bool gimple_resimplify2 (gimple_seq *seq, code_helper *res_code, tree type, tree *res_ops, tree (*valueize)(tree)) { if (constant_for_folding (res_ops[0]) && constant_for_folding (res_ops[1])) { tree tem = NULL_TREE; if (res_code->is_tree_code ()) tem = const_binop (*res_code, type, res_ops[0], res_ops[1]); else { tree decl = builtin_decl_implicit (*res_code); if (decl) { tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 2, false); if (tem) { /* fold_builtin_n wraps the result inside a NOP_EXPR. */ STRIP_NOPS (tem); tem = fold_convert (type, tem); } } } if (tem != NULL_TREE && CONSTANT_CLASS_P (tem)) { res_ops[0] = tem; res_ops[1] = NULL_TREE; res_ops[2] = NULL_TREE; *res_code = TREE_CODE (res_ops[0]); return true; } } /* Canonicalize operand order. */ bool canonicalized = false; if (res_code->is_tree_code () && (TREE_CODE_CLASS ((enum tree_code) *res_code) == tcc_comparison || commutative_tree_code (*res_code)) && tree_swap_operands_p (res_ops[0], res_ops[1], false)) { tree tem = res_ops[0]; res_ops[0] = res_ops[1]; res_ops[1] = tem; if (TREE_CODE_CLASS ((enum tree_code) *res_code) == tcc_comparison) *res_code = swap_tree_comparison (*res_code); canonicalized = true; } code_helper res_code2; tree res_ops2[3] = {}; if (gimple_simplify (&res_code2, res_ops2, seq, valueize, *res_code, type, res_ops[0], res_ops[1])) { *res_code = res_code2; res_ops[0] = res_ops2[0]; res_ops[1] = res_ops2[1]; res_ops[2] = res_ops2[2]; return true; } return canonicalized; }
tree expand_array_notation_exprs (tree t) { enum tree_code code; bool is_expr; location_t loc = UNKNOWN_LOCATION; if (!t) return t; loc = EXPR_LOCATION (t); code = TREE_CODE (t); is_expr = IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)); switch (code) { case ERROR_MARK: case IDENTIFIER_NODE: case VOID_CST: case INTEGER_CST: case REAL_CST: case FIXED_CST: case STRING_CST: case BLOCK: case PLACEHOLDER_EXPR: case FIELD_DECL: case VOID_TYPE: case REAL_TYPE: case SSA_NAME: case LABEL_DECL: case RESULT_DECL: case VAR_DECL: case PARM_DECL: case NON_LVALUE_EXPR: case NOP_EXPR: case ADDR_EXPR: case ARRAY_REF: case BIT_FIELD_REF: case VECTOR_CST: case COMPLEX_CST: return t; case INIT_EXPR: case MODIFY_EXPR: if (contains_array_notation_expr (t)) t = expand_an_in_modify_expr (loc, TREE_OPERAND (t, 0), NOP_EXPR, TREE_OPERAND (t, 1), tf_warning_or_error); return t; case MODOP_EXPR: if (contains_array_notation_expr (t) && !processing_template_decl) t = expand_an_in_modify_expr (loc, TREE_OPERAND (t, 0), TREE_CODE (TREE_OPERAND (t, 1)), TREE_OPERAND (t, 2), tf_warning_or_error); return t; case CONSTRUCTOR: return t; case BIND_EXPR: { BIND_EXPR_BODY (t) = expand_array_notation_exprs (BIND_EXPR_BODY (t)); return t; } case DECL_EXPR: if (contains_array_notation_expr (t)) { tree x = DECL_EXPR_DECL (t); if (DECL_INITIAL (x)) { location_t loc = DECL_SOURCE_LOCATION (x); tree lhs = x; tree rhs = DECL_INITIAL (x); DECL_INITIAL (x) = NULL; tree new_modify_expr = build_modify_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR, loc, rhs, TREE_TYPE(rhs)); t = expand_array_notation_exprs (new_modify_expr); } } return t; case STATEMENT_LIST: { tree_stmt_iterator i; for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) *tsi_stmt_ptr (i) = expand_array_notation_exprs (*tsi_stmt_ptr (i)); return t; } case OMP_PARALLEL: case OMP_TASK: case OMP_FOR: case OMP_SINGLE: case OMP_SECTION: case OMP_SECTIONS: case OMP_MASTER: case OMP_TASKGROUP: case OMP_ORDERED: case OMP_CRITICAL: case OMP_ATOMIC: case OMP_CLAUSE: case TARGET_EXPR: case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: case POINTER_TYPE: case ARRAY_TYPE: case RECORD_TYPE: case METHOD_TYPE: return t; case RETURN_EXPR: if (contains_array_notation_expr (t)) t = expand_return_expr (t); return t; case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: case AGGR_INIT_EXPR: case CALL_EXPR: t = expand_unary_array_notation_exprs (t); return t; case CONVERT_EXPR: case CLEANUP_POINT_EXPR: case EXPR_STMT: TREE_OPERAND (t, 0) = expand_array_notation_exprs (TREE_OPERAND (t, 0)); /* It is not necessary to wrap error_mark_node in EXPR_STMT. */ if (TREE_OPERAND (t, 0) == error_mark_node) return TREE_OPERAND (t, 0); return t; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case TRUTH_XOR_EXPR: case TRUTH_NOT_EXPR: case COND_EXPR: t = cp_expand_cond_array_notations (t); if (TREE_CODE (t) == COND_EXPR) { COND_EXPR_THEN (t) = expand_array_notation_exprs (COND_EXPR_THEN (t)); COND_EXPR_ELSE (t) = expand_array_notation_exprs (COND_EXPR_ELSE (t)); } return t; case FOR_STMT: if (contains_array_notation_expr (FOR_COND (t))) { error_at (EXPR_LOCATION (FOR_COND (t)), "array notation cannot be used in a condition for " "a for-loop"); return error_mark_node; } /* FIXME: Add a check for CILK_FOR_STMT here when we add Cilk tasking keywords. */ if (TREE_CODE (t) == FOR_STMT) { FOR_BODY (t) = expand_array_notation_exprs (FOR_BODY (t)); FOR_EXPR (t) = expand_array_notation_exprs (FOR_EXPR (t)); } else t = expand_array_notation_exprs (t); return t; case IF_STMT: t = cp_expand_cond_array_notations (t); /* If the above function added some extra instructions above the original if statement, then we can't assume it is still IF_STMT so we have to check again. */ if (TREE_CODE (t) == IF_STMT) { if (THEN_CLAUSE (t)) THEN_CLAUSE (t) = expand_array_notation_exprs (THEN_CLAUSE (t)); if (ELSE_CLAUSE (t)) ELSE_CLAUSE (t) = expand_array_notation_exprs (ELSE_CLAUSE (t)); } else t = expand_array_notation_exprs (t); return t; case SWITCH_STMT: if (contains_array_notation_expr (SWITCH_STMT_COND (t))) { error_at (EXPR_LOCATION (SWITCH_STMT_COND (t)), "array notation cannot be used as a condition for " "switch statement"); return error_mark_node; } if (SWITCH_STMT_BODY (t)) SWITCH_STMT_BODY (t) = expand_array_notation_exprs (SWITCH_STMT_BODY (t)); return t; case WHILE_STMT: if (contains_array_notation_expr (WHILE_COND (t))) { if (EXPR_LOCATION (WHILE_COND (t)) != UNKNOWN_LOCATION) loc = EXPR_LOCATION (WHILE_COND (t)); error_at (loc, "array notation cannot be used as a condition for " "while statement"); return error_mark_node; } if (WHILE_BODY (t)) WHILE_BODY (t) = expand_array_notation_exprs (WHILE_BODY (t)); return t; case DO_STMT: if (contains_array_notation_expr (DO_COND (t))) { error_at (EXPR_LOCATION (DO_COND (t)), "array notation cannot be used as a condition for a " "do-while statement"); return error_mark_node; } if (DO_BODY (t)) DO_BODY (t) = expand_array_notation_exprs (DO_BODY (t)); return t; default: if (is_expr) { int i, len; /* Walk over all the sub-trees of this operand. */ len = TREE_CODE_LENGTH (code); /* Go through the subtrees. We need to do this in forward order so that the scope of a FOR_EXPR is handled properly. */ for (i = 0; i < len; ++i) TREE_OPERAND (t, i) = expand_array_notation_exprs (TREE_OPERAND (t, i)); } return t; } return t; }
static void dequeue_and_dump (dump_info_p di) { dump_queue_p dq; splay_tree_node stn; dump_node_info_p dni; tree t; unsigned int index; enum tree_code code; enum tree_code_class code_class; const char* code_name; /* Get the next node from the queue. */ dq = di->queue; stn = dq->node; t = (tree) stn->key; dni = (dump_node_info_p) stn->value; index = dni->index; /* Remove the node from the queue, and put it on the free list. */ di->queue = dq->next; if (!di->queue) di->queue_end = 0; dq->next = di->free_list; di->free_list = dq; /* Print the node index. */ dump_index (di, index); /* And the type of node this is. */ if (dni->binfo_p) code_name = "binfo"; else code_name = tree_code_name[(int) TREE_CODE (t)]; fprintf (di->stream, "%-16s ", code_name); di->column = 25; /* Figure out what kind of node this is. */ code = TREE_CODE (t); code_class = TREE_CODE_CLASS (code); /* Although BINFOs are TREE_VECs, we dump them specially so as to be more informative. */ if (dni->binfo_p) { unsigned ix; tree base; VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t); dump_child ("type", BINFO_TYPE (t)); if (BINFO_VIRTUAL_P (t)) dump_string_field (di, "spec", "virt"); dump_int (di, "bases", BINFO_N_BASE_BINFOS (t)); for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++) { tree access = (accesses ? VEC_index (tree, accesses, ix) : access_public_node); const char *string = NULL; if (access == access_public_node) string = "pub"; else if (access == access_protected_node) string = "prot"; else if (access == access_private_node) string = "priv"; else gcc_unreachable (); dump_string_field (di, "accs", string); queue_and_dump_index (di, "binf", base, DUMP_BINFO); } goto done; } /* We can knock off a bunch of expression nodes in exactly the same way. */ if (IS_EXPR_CODE_CLASS (code_class)) { /* If we're dumping children, dump them now. */ queue_and_dump_type (di, t); switch (code_class) { case tcc_unary: dump_child ("op 0", TREE_OPERAND (t, 0)); break; case tcc_binary: case tcc_comparison: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case tcc_expression: case tcc_reference: case tcc_statement: case tcc_vl_exp: /* These nodes are handled explicitly below. */ break; default: gcc_unreachable (); } } else if (DECL_P (t)) { expanded_location xloc; /* All declarations have names. */ if (DECL_NAME (t)) dump_child ("name", DECL_NAME (t)); if (DECL_ASSEMBLER_NAME_SET_P (t) && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t)) dump_child ("mngl", DECL_ASSEMBLER_NAME (t)); if (DECL_ABSTRACT_ORIGIN (t)) dump_child ("orig", DECL_ABSTRACT_ORIGIN (t)); /* And types. */ queue_and_dump_type (di, t); dump_child ("scpe", DECL_CONTEXT (t)); /* And a source position. */ xloc = expand_location (DECL_SOURCE_LOCATION (t)); if (xloc.file) { const char *filename = lbasename (xloc.file); dump_maybe_newline (di); fprintf (di->stream, "srcp: %s:%-6d ", filename, xloc.line); di->column += 6 + strlen (filename) + 8; } /* And any declaration can be compiler-generated. */ if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON) && DECL_ARTIFICIAL (t)) dump_string_field (di, "note", "artificial"); if (DECL_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL)) dump_child ("chain", DECL_CHAIN (t)); } else if (code_class == tcc_type) { /* All types have qualifiers. */ int quals = lang_hooks.tree_dump.type_quals (t); if (quals != TYPE_UNQUALIFIED) { fprintf (di->stream, "qual: %c%c%c ", (quals & TYPE_QUAL_CONST) ? 'c' : ' ', (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ', (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' '); di->column += 14; } /* All types have associated declarations. */ dump_child ("name", TYPE_NAME (t)); /* All types have a main variant. */ if (TYPE_MAIN_VARIANT (t) != t) dump_child ("unql", TYPE_MAIN_VARIANT (t)); /* And sizes. */ dump_child ("size", TYPE_SIZE (t)); /* All types have alignments. */ dump_int (di, "algn", TYPE_ALIGN (t)); } else if (code_class == tcc_constant) /* All constants can have types. */ queue_and_dump_type (di, t); /* Give the language-specific code a chance to print something. If it's completely taken care of things, don't bother printing anything more ourselves. */ if (lang_hooks.tree_dump.dump_tree (di, t)) goto done; /* Now handle the various kinds of nodes. */ switch (code) { int i; case IDENTIFIER_NODE: dump_string_field (di, "strg", IDENTIFIER_POINTER (t)); dump_int (di, "lngt", IDENTIFIER_LENGTH (t)); break; case TREE_LIST: dump_child ("purp", TREE_PURPOSE (t)); dump_child ("valu", TREE_VALUE (t)); dump_child ("chan", TREE_CHAIN (t)); break; case STATEMENT_LIST: { tree_stmt_iterator it; for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, tsi_stmt (it)); } } break; case TREE_VEC: dump_int (di, "lngt", TREE_VEC_LENGTH (t)); for (i = 0; i < TREE_VEC_LENGTH (t); ++i) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, TREE_VEC_ELT (t, i)); } break; case INTEGER_TYPE: case ENUMERAL_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed"); dump_child ("min", TYPE_MIN_VALUE (t)); dump_child ("max", TYPE_MAX_VALUE (t)); if (code == ENUMERAL_TYPE) dump_child ("csts", TYPE_VALUES (t)); break; case REAL_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); break; case FIXED_POINT_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed"); dump_string_field (di, "saturating", TYPE_SATURATING (t) ? "saturating": "non-saturating"); break; case POINTER_TYPE: dump_child ("ptd", TREE_TYPE (t)); break; case REFERENCE_TYPE: dump_child ("refd", TREE_TYPE (t)); break; case METHOD_TYPE: dump_child ("clas", TYPE_METHOD_BASETYPE (t)); /* Fall through. */ case FUNCTION_TYPE: dump_child ("retn", TREE_TYPE (t)); dump_child ("prms", TYPE_ARG_TYPES (t)); break; case ARRAY_TYPE: dump_child ("elts", TREE_TYPE (t)); dump_child ("domn", TYPE_DOMAIN (t)); break; case RECORD_TYPE: case UNION_TYPE: if (TREE_CODE (t) == RECORD_TYPE) dump_string_field (di, "tag", "struct"); else dump_string_field (di, "tag", "union"); dump_child ("flds", TYPE_FIELDS (t)); dump_child ("fncs", TYPE_METHODS (t)); queue_and_dump_index (di, "binf", TYPE_BINFO (t), DUMP_BINFO); break; case CONST_DECL: dump_child ("cnst", DECL_INITIAL (t)); break; case DEBUG_EXPR_DECL: dump_int (di, "-uid", DEBUG_TEMP_UID (t)); /* Fall through. */ case VAR_DECL: case PARM_DECL: case FIELD_DECL: case RESULT_DECL: if (TREE_CODE (t) == PARM_DECL) dump_child ("argt", DECL_ARG_TYPE (t)); else dump_child ("init", DECL_INITIAL (t)); dump_child ("size", DECL_SIZE (t)); dump_int (di, "algn", DECL_ALIGN (t)); if (TREE_CODE (t) == FIELD_DECL) { if (DECL_FIELD_OFFSET (t)) dump_child ("bpos", bit_position (t)); } else if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL) { dump_int (di, "used", TREE_USED (t)); if (DECL_REGISTER (t)) dump_string_field (di, "spec", "register"); } break; case FUNCTION_DECL: dump_child ("args", DECL_ARGUMENTS (t)); if (DECL_EXTERNAL (t)) dump_string_field (di, "body", "undefined"); if (TREE_PUBLIC (t)) dump_string_field (di, "link", "extern"); else dump_string_field (di, "link", "static"); if (DECL_SAVED_TREE (t) && !dump_flag (di, TDF_SLIM, t)) dump_child ("body", DECL_SAVED_TREE (t)); break; case INTEGER_CST: if (TREE_INT_CST_HIGH (t)) dump_int (di, "high", TREE_INT_CST_HIGH (t)); dump_int (di, "low", TREE_INT_CST_LOW (t)); break; case STRING_CST: fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t)); dump_int (di, "lngt", TREE_STRING_LENGTH (t)); break; case REAL_CST: dump_real (di, "valu", TREE_REAL_CST_PTR (t)); break; case FIXED_CST: dump_fixed (di, "valu", TREE_FIXED_CST_PTR (t)); break; case TRUTH_NOT_EXPR: case ADDR_EXPR: case INDIRECT_REF: case CLEANUP_POINT_EXPR: case SAVE_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: /* These nodes are unary, but do not have code class `1'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); break; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case INIT_EXPR: case MODIFY_EXPR: case COMPOUND_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: /* These nodes are binary, but do not have code class `2'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case COMPONENT_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); break; case ARRAY_REF: case ARRAY_RANGE_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); dump_child ("op 3", TREE_OPERAND (t, 3)); break; case COND_EXPR: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); break; case TRY_FINALLY_EXPR: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case CALL_EXPR: { int i = 0; tree arg; call_expr_arg_iterator iter; dump_child ("fn", CALL_EXPR_FN (t)); FOR_EACH_CALL_EXPR_ARG (arg, iter, t) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, arg); i++; } } break; case CONSTRUCTOR: { unsigned HOST_WIDE_INT cnt; tree index, value; dump_int (di, "lngt", VEC_length (constructor_elt, CONSTRUCTOR_ELTS (t))); FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value) { dump_child ("idx", index); dump_child ("val", value); } }
tree convert_to_void (tree expr, const char *implicit, tsubst_flags_t complain) { if (expr == error_mark_node || TREE_TYPE (expr) == error_mark_node) return error_mark_node; if (!TREE_TYPE (expr)) return expr; if (invalid_nonstatic_memfn_p (expr, complain)) return error_mark_node; if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR) { if (complain & tf_error) error ("pseudo-destructor is not called"); return error_mark_node; } if (VOID_TYPE_P (TREE_TYPE (expr))) return expr; switch (TREE_CODE (expr)) { case COND_EXPR: { /* The two parts of a cond expr might be separate lvalues. */ tree op1 = TREE_OPERAND (expr,1); tree op2 = TREE_OPERAND (expr,2); tree new_op1 = convert_to_void (op1, (implicit && !TREE_SIDE_EFFECTS (op2) ? "second operand of conditional" : NULL), complain); tree new_op2 = convert_to_void (op2, (implicit && !TREE_SIDE_EFFECTS (op1) ? "third operand of conditional" : NULL), complain); expr = build3 (COND_EXPR, TREE_TYPE (new_op1), TREE_OPERAND (expr, 0), new_op1, new_op2); break; } case COMPOUND_EXPR: { /* The second part of a compound expr contains the value. */ tree op1 = TREE_OPERAND (expr,1); tree new_op1 = convert_to_void (op1, (implicit && !TREE_NO_WARNING (expr) ? "right-hand operand of comma" : NULL), complain); if (new_op1 != op1) { tree t = build2 (COMPOUND_EXPR, TREE_TYPE (new_op1), TREE_OPERAND (expr, 0), new_op1); expr = t; } break; } case NON_LVALUE_EXPR: case NOP_EXPR: /* These have already decayed to rvalue. */ break; case CALL_EXPR: /* We have a special meaning for volatile void fn(). */ break; case INDIRECT_REF: { tree type = TREE_TYPE (expr); int is_reference = TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE; int is_volatile = TYPE_VOLATILE (type); int is_complete = COMPLETE_TYPE_P (complete_type (type)); /* Can't load the value if we don't know the type. */ if (is_volatile && !is_complete) { if (complain & tf_warning) warning (0, "object of incomplete type %qT will not be accessed in %s", type, implicit ? implicit : "void context"); } /* Don't load the value if this is an implicit dereference, or if the type needs to be handled by ctors/dtors. */ else if (is_volatile && (is_reference || TREE_ADDRESSABLE (type))) { if (complain & tf_warning) warning (0, "object of type %qT will not be accessed in %s", TREE_TYPE (TREE_OPERAND (expr, 0)), implicit ? implicit : "void context"); } if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE (type)) expr = TREE_OPERAND (expr, 0); break; } case VAR_DECL: { /* External variables might be incomplete. */ tree type = TREE_TYPE (expr); int is_complete = COMPLETE_TYPE_P (complete_type (type)); if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning)) warning (0, "object %qE of incomplete type %qT will not be accessed in %s", expr, type, implicit ? implicit : "void context"); break; } case TARGET_EXPR: /* Don't bother with the temporary object returned from a function if we don't use it and don't need to destroy it. We'll still allocate space for it in expand_call or declare_return_variable, but we don't need to track it through all the tree phases. */ if (TARGET_EXPR_IMPLICIT_P (expr) && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (expr))) { tree init = TARGET_EXPR_INITIAL (expr); if (TREE_CODE (init) == AGGR_INIT_EXPR && !AGGR_INIT_VIA_CTOR_P (init)) { tree fn = AGGR_INIT_EXPR_FN (init); expr = build_call_array (TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), fn, aggr_init_expr_nargs (init), AGGR_INIT_EXPR_ARGP (init)); } } break; default:; } { tree probe = expr; if (TREE_CODE (probe) == ADDR_EXPR) probe = TREE_OPERAND (expr, 0); if (type_unknown_p (probe)) { /* [over.over] enumerates the places where we can take the address of an overloaded function, and this is not one of them. */ if (complain & tf_error) error ("%s cannot resolve address of overloaded function", implicit ? implicit : "void cast"); else return error_mark_node; expr = void_zero_node; } else if (implicit && probe == expr && is_overloaded_fn (probe)) { /* Only warn when there is no &. */ if (complain & tf_warning) warning (OPT_Waddress, "%s is a reference, not call, to function %qE", implicit, expr); if (TREE_CODE (expr) == COMPONENT_REF) expr = TREE_OPERAND (expr, 0); } } if (expr != error_mark_node && !VOID_TYPE_P (TREE_TYPE (expr))) { if (implicit && warn_unused_value && !TREE_NO_WARNING (expr) && !processing_template_decl) { /* The middle end does not warn about expressions that have been explicitly cast to void, so we must do so here. */ if (!TREE_SIDE_EFFECTS (expr)) { if (complain & tf_warning) warning (OPT_Wunused_value, "%s has no effect", implicit); } else { tree e; enum tree_code code; enum tree_code_class tclass; e = expr; /* We might like to warn about (say) "(int) f()", as the cast has no effect, but the compiler itself will generate implicit conversions under some circumstances. (For example a block copy will be turned into a call to "__builtin_memcpy", with a conversion of the return value to an appropriate type.) So, to avoid false positives, we strip conversions. Do not use STRIP_NOPs because it will not strip conversions to "void", as that is not a mode-preserving conversion. */ while (TREE_CODE (e) == NOP_EXPR) e = TREE_OPERAND (e, 0); code = TREE_CODE (e); tclass = TREE_CODE_CLASS (code); if ((tclass == tcc_comparison || tclass == tcc_unary || (tclass == tcc_binary && !(code == MODIFY_EXPR || code == INIT_EXPR || code == PREDECREMENT_EXPR || code == PREINCREMENT_EXPR || code == POSTDECREMENT_EXPR || code == POSTINCREMENT_EXPR))) && (complain & tf_warning)) warning (OPT_Wunused_value, "value computed is not used"); } } expr = build1 (CONVERT_EXPR, void_type_node, expr); } if (! TREE_SIDE_EFFECTS (expr)) expr = void_zero_node; return expr; }
static tree scan_function (tree *tp, int *walk_subtrees, void *data) { struct cgraph_node *fn = data; tree t = *tp; funct_state local = get_function_state (fn); switch (TREE_CODE (t)) { case VAR_DECL: if (DECL_INITIAL (t)) walk_tree (&DECL_INITIAL (t), scan_function, fn, visited_nodes); *walk_subtrees = 0; break; case MODIFY_EXPR: { /* First look on the lhs and see what variable is stored to */ tree lhs = TREE_OPERAND (t, 0); tree rhs = TREE_OPERAND (t, 1); check_lhs_var (local, lhs); /* For the purposes of figuring out what the cast affects */ /* Next check the operands on the rhs to see if they are ok. */ switch (TREE_CODE_CLASS (TREE_CODE (rhs))) { case tcc_binary: { tree op0 = TREE_OPERAND (rhs, 0); tree op1 = TREE_OPERAND (rhs, 1); check_rhs_var (local, op0); check_rhs_var (local, op1); } break; case tcc_unary: { tree op0 = TREE_OPERAND (rhs, 0); check_rhs_var (local, op0); } break; case tcc_reference: check_rhs_var (local, rhs); break; case tcc_declaration: check_rhs_var (local, rhs); break; case tcc_expression: switch (TREE_CODE (rhs)) { case ADDR_EXPR: check_rhs_var (local, rhs); break; case CALL_EXPR: check_call (local, rhs); break; default: break; } break; default: break; } *walk_subtrees = 0; } break; case ADDR_EXPR: /* This case is here to find addresses on rhs of constructors in decl_initial of static variables. */ check_rhs_var (local, t); *walk_subtrees = 0; break; case LABEL_EXPR: if (DECL_NONLOCAL (TREE_OPERAND (t, 0))) /* Target of long jump. */ local->pure_const_state = IPA_NEITHER; break; case CALL_EXPR: check_call (local, t); *walk_subtrees = 0; break; case ASM_EXPR: get_asm_expr_operands (local, t); *walk_subtrees = 0; break; default: break; } return NULL; }
static bool ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv, basic_block outer_cond_bb, bool outer_inv, bool result_inv) { gimple_stmt_iterator gsi; gimple inner_stmt, outer_stmt; gcond *inner_cond, *outer_cond; tree name1, name2, bit1, bit2, bits1, bits2; inner_stmt = last_stmt (inner_cond_bb); if (!inner_stmt || gimple_code (inner_stmt) != GIMPLE_COND) return false; inner_cond = as_a <gcond *> (inner_stmt); outer_stmt = last_stmt (outer_cond_bb); if (!outer_stmt || gimple_code (outer_stmt) != GIMPLE_COND) return false; outer_cond = as_a <gcond *> (outer_stmt); /* See if we test a single bit of the same name in both tests. In that case remove the outer test, merging both else edges, and change the inner one to test for name & (bit1 | bit2) == (bit1 | bit2). */ if (recognize_single_bit_test (inner_cond, &name1, &bit1, inner_inv) && recognize_single_bit_test (outer_cond, &name2, &bit2, outer_inv) && name1 == name2) { tree t, t2; /* Do it. */ gsi = gsi_for_stmt (inner_cond); t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1), build_int_cst (TREE_TYPE (name1), 1), bit1); t2 = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1), build_int_cst (TREE_TYPE (name1), 1), bit2); t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), t, t2); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); t2 = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t); t2 = force_gimple_operand_gsi (&gsi, t2, true, NULL_TREE, true, GSI_SAME_STMT); t = fold_build2 (result_inv ? NE_EXPR : EQ_EXPR, boolean_type_node, t2, t); t = canonicalize_cond_expr_cond (t); if (!t) return false; gimple_cond_set_condition_from_tree (inner_cond, t); update_stmt (inner_cond); /* Leave CFG optimization to cfg_cleanup. */ gimple_cond_set_condition_from_tree (outer_cond, outer_inv ? boolean_false_node : boolean_true_node); update_stmt (outer_cond); if (dump_file) { fprintf (dump_file, "optimizing double bit test to "); print_generic_expr (dump_file, name1, 0); fprintf (dump_file, " & T == T\nwith temporary T = (1 << "); print_generic_expr (dump_file, bit1, 0); fprintf (dump_file, ") | (1 << "); print_generic_expr (dump_file, bit2, 0); fprintf (dump_file, ")\n"); } return true; } /* See if we have two bit tests of the same name in both tests. In that case remove the outer test and change the inner one to test for name & (bits1 | bits2) != 0. */ else if (recognize_bits_test (inner_cond, &name1, &bits1, !inner_inv) && recognize_bits_test (outer_cond, &name2, &bits2, !outer_inv)) { gimple_stmt_iterator gsi; tree t; /* Find the common name which is bit-tested. */ if (name1 == name2) ; else if (bits1 == bits2) { t = name2; name2 = bits2; bits2 = t; t = name1; name1 = bits1; bits1 = t; } else if (name1 == bits2) { t = name2; name2 = bits2; bits2 = t; } else if (bits1 == name2) { t = name1; name1 = bits1; bits1 = t; } else return false; /* As we strip non-widening conversions in finding a common name that is tested make sure to end up with an integral type for building the bit operations. */ if (TYPE_PRECISION (TREE_TYPE (bits1)) >= TYPE_PRECISION (TREE_TYPE (bits2))) { bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1); name1 = fold_convert (TREE_TYPE (bits1), name1); bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2); bits2 = fold_convert (TREE_TYPE (bits1), bits2); } else { bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2); name1 = fold_convert (TREE_TYPE (bits2), name1); bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1); bits1 = fold_convert (TREE_TYPE (bits2), bits1); } /* Do it. */ gsi = gsi_for_stmt (inner_cond); t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), bits1, bits2); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); t = fold_build2 (result_inv ? NE_EXPR : EQ_EXPR, boolean_type_node, t, build_int_cst (TREE_TYPE (t), 0)); t = canonicalize_cond_expr_cond (t); if (!t) return false; gimple_cond_set_condition_from_tree (inner_cond, t); update_stmt (inner_cond); /* Leave CFG optimization to cfg_cleanup. */ gimple_cond_set_condition_from_tree (outer_cond, outer_inv ? boolean_false_node : boolean_true_node); update_stmt (outer_cond); if (dump_file) { fprintf (dump_file, "optimizing bits or bits test to "); print_generic_expr (dump_file, name1, 0); fprintf (dump_file, " & T != 0\nwith temporary T = "); print_generic_expr (dump_file, bits1, 0); fprintf (dump_file, " | "); print_generic_expr (dump_file, bits2, 0); fprintf (dump_file, "\n"); } return true; } /* See if we have two comparisons that we can merge into one. */ else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison) { tree t; enum tree_code inner_cond_code = gimple_cond_code (inner_cond); enum tree_code outer_cond_code = gimple_cond_code (outer_cond); /* Invert comparisons if necessary (and possible). */ if (inner_inv) inner_cond_code = invert_tree_comparison (inner_cond_code, HONOR_NANS (gimple_cond_lhs (inner_cond))); if (inner_cond_code == ERROR_MARK) return false; if (outer_inv) outer_cond_code = invert_tree_comparison (outer_cond_code, HONOR_NANS (gimple_cond_lhs (outer_cond))); if (outer_cond_code == ERROR_MARK) return false; /* Don't return false so fast, try maybe_fold_or_comparisons? */ if (!(t = maybe_fold_and_comparisons (inner_cond_code, gimple_cond_lhs (inner_cond), gimple_cond_rhs (inner_cond), outer_cond_code, gimple_cond_lhs (outer_cond), gimple_cond_rhs (outer_cond)))) { tree t1, t2; gimple_stmt_iterator gsi; if (!LOGICAL_OP_NON_SHORT_CIRCUIT) return false; /* Only do this optimization if the inner bb contains only the conditional. */ if (!gsi_one_before_end_p (gsi_start_nondebug_after_labels_bb (inner_cond_bb))) return false; t1 = fold_build2_loc (gimple_location (inner_cond), inner_cond_code, boolean_type_node, gimple_cond_lhs (inner_cond), gimple_cond_rhs (inner_cond)); t2 = fold_build2_loc (gimple_location (outer_cond), outer_cond_code, boolean_type_node, gimple_cond_lhs (outer_cond), gimple_cond_rhs (outer_cond)); t = fold_build2_loc (gimple_location (inner_cond), TRUTH_AND_EXPR, boolean_type_node, t1, t2); if (result_inv) { t = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (t), t); result_inv = false; } gsi = gsi_for_stmt (inner_cond); t = force_gimple_operand_gsi_1 (&gsi, t, is_gimple_condexpr, NULL, true, GSI_SAME_STMT); } if (result_inv) t = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (t), t); t = canonicalize_cond_expr_cond (t); if (!t) return false; gimple_cond_set_condition_from_tree (inner_cond, t); update_stmt (inner_cond); /* Leave CFG optimization to cfg_cleanup. */ gimple_cond_set_condition_from_tree (outer_cond, outer_inv ? boolean_false_node : boolean_true_node); update_stmt (outer_cond); if (dump_file) { fprintf (dump_file, "optimizing two comparisons to "); print_generic_expr (dump_file, t, 0); fprintf (dump_file, "\n"); } return true; } return false; }
void print_node_brief (FILE *file, const char *prefix, const_tree node, int indent) { enum tree_code_class tclass; if (node == 0) return; tclass = TREE_CODE_CLASS (TREE_CODE (node)); /* Always print the slot this node is in, and its code, address and name if any. */ if (indent > 0) fprintf (file, " "); fprintf (file, "%s <%s", prefix, get_tree_code_name (TREE_CODE (node))); dump_addr (file, " ", node); if (tclass == tcc_declaration) { if (DECL_NAME (node)) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); else if (TREE_CODE (node) == LABEL_DECL && LABEL_DECL_UID (node) != -1) { if (dump_flags & TDF_NOUID) fprintf (file, " L.xxxx"); else fprintf (file, " L.%d", (int) LABEL_DECL_UID (node)); } else { if (dump_flags & TDF_NOUID) fprintf (file, " %c.xxxx", TREE_CODE (node) == CONST_DECL ? 'C' : 'D'); else fprintf (file, " %c.%u", TREE_CODE (node) == CONST_DECL ? 'C' : 'D', DECL_UID (node)); } } else if (tclass == tcc_type) { if (TYPE_NAME (node)) { if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node))); else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL && DECL_NAME (TYPE_NAME (node))) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)))); } if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); } if (TREE_CODE (node) == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (node)); /* We might as well always print the value of an integer or real. */ if (TREE_CODE (node) == INTEGER_CST) { if (TREE_OVERFLOW (node)) fprintf (file, " overflow"); fprintf (file, " "); print_dec (node, file, TYPE_SIGN (TREE_TYPE (node))); } if (TREE_CODE (node) == REAL_CST) { REAL_VALUE_TYPE d; if (TREE_OVERFLOW (node)) fprintf (file, " overflow"); d = TREE_REAL_CST (node); if (REAL_VALUE_ISINF (d)) fprintf (file, REAL_VALUE_NEGATIVE (d) ? " -Inf" : " Inf"); else if (REAL_VALUE_ISNAN (d)) fprintf (file, " Nan"); else { char string[60]; real_to_decimal (string, &d, sizeof (string), 0, 1); fprintf (file, " %s", string); } } if (TREE_CODE (node) == FIXED_CST) { FIXED_VALUE_TYPE f; char string[60]; if (TREE_OVERFLOW (node)) fprintf (file, " overflow"); f = TREE_FIXED_CST (node); fixed_to_decimal (string, &f, sizeof (string)); fprintf (file, " %s", string); } fprintf (file, ">"); }
int java_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) { enum tree_code code = TREE_CODE (*expr_p); switch (code) { case BLOCK: *expr_p = java_gimplify_block (*expr_p); break; case VAR_DECL: *expr_p = java_replace_reference (*expr_p, /* want_lvalue */ false); return GS_UNHANDLED; case MODIFY_EXPR: return java_gimplify_modify_expr (expr_p); case SAVE_EXPR: /* Note that we can see <save_expr NULL> if the save_expr was already handled by gimplify_save_expr. */ if (TREE_OPERAND (*expr_p, 0) != NULL_TREE && TREE_CODE (TREE_OPERAND (*expr_p, 0)) == VAR_DECL) TREE_OPERAND (*expr_p, 0) = java_replace_reference (TREE_OPERAND (*expr_p, 0), /* want_lvalue */ false); return GS_UNHANDLED; case POSTINCREMENT_EXPR: case POSTDECREMENT_EXPR: case PREINCREMENT_EXPR: case PREDECREMENT_EXPR: return java_gimplify_self_mod_expr (expr_p, pre_p, post_p); /* These should already be lowered before we get here. */ case URSHIFT_EXPR: case COMPARE_EXPR: case COMPARE_L_EXPR: case COMPARE_G_EXPR: gcc_unreachable (); default: /* Java insists on strict left-to-right evaluation of expressions. A problem may arise if a variable used in the LHS of a binary operation is altered by an assignment to that value in the RHS before we've performed the operation. So, we always copy every LHS to a temporary variable. FIXME: Are there any other cases where we should do this? Parameter lists, maybe? Or perhaps that's unnecessary because the front end already generates SAVE_EXPRs. */ if (TREE_CODE_CLASS (code) == tcc_binary || TREE_CODE_CLASS (code) == tcc_comparison) { enum gimplify_status stat = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_gimple_formal_tmp_var, fb_rvalue); if (stat == GS_ERROR) return stat; } return GS_UNHANDLED; } return GS_OK; }