tree gimple_simplify (enum tree_code code, tree type, tree op0, tree op1, tree op2, gimple_seq *seq, tree (*valueize)(tree)) { if (constant_for_folding (op0) && constant_for_folding (op1) && constant_for_folding (op2)) { tree res = fold_ternary/*_to_constant */ (code, type, op0, op1, op2); if (res != NULL_TREE && CONSTANT_CLASS_P (res)) return res; } /* Canonicalize operand order both for matching and fallback stmt generation. */ if (commutative_ternary_tree_code (code) && tree_swap_operands_p (op0, op1, false)) { tree tem = op0; op0 = op1; op1 = tem; } code_helper rcode; tree ops[3] = {}; if (!gimple_simplify (&rcode, ops, seq, valueize, code, type, op0, op1, op2)) return NULL_TREE; return maybe_push_res_to_seq (rcode, type, ops, seq); }
bool gimple_resimplify3 (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]) && constant_for_folding (res_ops[2])) { tree tem = NULL_TREE; if (res_code->is_tree_code ()) tem = fold_ternary/*_to_constant*/ (*res_code, type, res_ops[0], res_ops[1], res_ops[2]); else tem = fold_const_call (combined_fn (*res_code), type, res_ops[0], res_ops[1], res_ops[2]); 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 () && commutative_ternary_tree_code (*res_code) && tree_swap_operands_p (res_ops[0], res_ops[1])) { std::swap (res_ops[0], res_ops[1]); 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_ops[2])) { *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; }
static bool gimple_resimplify3 (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]) && constant_for_folding (res_ops[2])) { tree tem = NULL_TREE; if (res_code->is_tree_code ()) tem = fold_ternary/*_to_constant*/ (*res_code, type, res_ops[0], res_ops[1], res_ops[2]); else { tree decl = builtin_decl_implicit (*res_code); if (decl) { tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 3, 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 () && commutative_ternary_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; 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_ops[2])) { *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; }
static bool hashable_expr_equal_p (const struct hashable_expr *expr0, const struct hashable_expr *expr1) { tree type0 = expr0->type; tree type1 = expr1->type; /* If either type is NULL, there is nothing to check. */ if ((type0 == NULL_TREE) ^ (type1 == NULL_TREE)) return false; /* If both types don't have the same signedness, precision, and mode, then we can't consider them equal. */ if (type0 != type1 && (TREE_CODE (type0) == ERROR_MARK || TREE_CODE (type1) == ERROR_MARK || TYPE_UNSIGNED (type0) != TYPE_UNSIGNED (type1) || TYPE_PRECISION (type0) != TYPE_PRECISION (type1) || TYPE_MODE (type0) != TYPE_MODE (type1))) return false; if (expr0->kind != expr1->kind) return false; switch (expr0->kind) { case EXPR_SINGLE: return operand_equal_p (expr0->ops.single.rhs, expr1->ops.single.rhs, 0); case EXPR_UNARY: if (expr0->ops.unary.op != expr1->ops.unary.op) return false; if ((CONVERT_EXPR_CODE_P (expr0->ops.unary.op) || expr0->ops.unary.op == NON_LVALUE_EXPR) && TYPE_UNSIGNED (expr0->type) != TYPE_UNSIGNED (expr1->type)) return false; return operand_equal_p (expr0->ops.unary.opnd, expr1->ops.unary.opnd, 0); case EXPR_BINARY: if (expr0->ops.binary.op != expr1->ops.binary.op) return false; if (operand_equal_p (expr0->ops.binary.opnd0, expr1->ops.binary.opnd0, 0) && operand_equal_p (expr0->ops.binary.opnd1, expr1->ops.binary.opnd1, 0)) return true; /* For commutative ops, allow the other order. */ return (commutative_tree_code (expr0->ops.binary.op) && operand_equal_p (expr0->ops.binary.opnd0, expr1->ops.binary.opnd1, 0) && operand_equal_p (expr0->ops.binary.opnd1, expr1->ops.binary.opnd0, 0)); case EXPR_TERNARY: if (expr0->ops.ternary.op != expr1->ops.ternary.op || !operand_equal_p (expr0->ops.ternary.opnd2, expr1->ops.ternary.opnd2, 0)) return false; if (operand_equal_p (expr0->ops.ternary.opnd0, expr1->ops.ternary.opnd0, 0) && operand_equal_p (expr0->ops.ternary.opnd1, expr1->ops.ternary.opnd1, 0)) return true; /* For commutative ops, allow the other order. */ return (commutative_ternary_tree_code (expr0->ops.ternary.op) && operand_equal_p (expr0->ops.ternary.opnd0, expr1->ops.ternary.opnd1, 0) && operand_equal_p (expr0->ops.ternary.opnd1, expr1->ops.ternary.opnd0, 0)); case EXPR_CALL: { size_t i; /* If the calls are to different functions, then they clearly cannot be equal. */ if (!gimple_call_same_target_p (expr0->ops.call.fn_from, expr1->ops.call.fn_from)) return false; if (! expr0->ops.call.pure) return false; if (expr0->ops.call.nargs != expr1->ops.call.nargs) return false; for (i = 0; i < expr0->ops.call.nargs; i++) if (! operand_equal_p (expr0->ops.call.args[i], expr1->ops.call.args[i], 0)) return false; if (stmt_could_throw_p (expr0->ops.call.fn_from)) { int lp0 = lookup_stmt_eh_lp (expr0->ops.call.fn_from); int lp1 = lookup_stmt_eh_lp (expr1->ops.call.fn_from); if ((lp0 > 0 || lp1 > 0) && lp0 != lp1) return false; } return true; } case EXPR_PHI: { size_t i; if (expr0->ops.phi.nargs != expr1->ops.phi.nargs) return false; for (i = 0; i < expr0->ops.phi.nargs; i++) if (! operand_equal_p (expr0->ops.phi.args[i], expr1->ops.phi.args[i], 0)) return false; return true; } default: gcc_unreachable (); } }
static void add_hashable_expr (const struct hashable_expr *expr, hash &hstate) { switch (expr->kind) { case EXPR_SINGLE: inchash::add_expr (expr->ops.single.rhs, hstate); break; case EXPR_UNARY: hstate.add_object (expr->ops.unary.op); /* Make sure to include signedness in the hash computation. Don't hash the type, that can lead to having nodes which compare equal according to operand_equal_p, but which have different hash codes. */ if (CONVERT_EXPR_CODE_P (expr->ops.unary.op) || expr->ops.unary.op == NON_LVALUE_EXPR) hstate.add_int (TYPE_UNSIGNED (expr->type)); inchash::add_expr (expr->ops.unary.opnd, hstate); break; case EXPR_BINARY: hstate.add_object (expr->ops.binary.op); if (commutative_tree_code (expr->ops.binary.op)) inchash::add_expr_commutative (expr->ops.binary.opnd0, expr->ops.binary.opnd1, hstate); else { inchash::add_expr (expr->ops.binary.opnd0, hstate); inchash::add_expr (expr->ops.binary.opnd1, hstate); } break; case EXPR_TERNARY: hstate.add_object (expr->ops.ternary.op); if (commutative_ternary_tree_code (expr->ops.ternary.op)) inchash::add_expr_commutative (expr->ops.ternary.opnd0, expr->ops.ternary.opnd1, hstate); else { inchash::add_expr (expr->ops.ternary.opnd0, hstate); inchash::add_expr (expr->ops.ternary.opnd1, hstate); } inchash::add_expr (expr->ops.ternary.opnd2, hstate); break; case EXPR_CALL: { size_t i; enum tree_code code = CALL_EXPR; gcall *fn_from; hstate.add_object (code); fn_from = expr->ops.call.fn_from; if (gimple_call_internal_p (fn_from)) hstate.merge_hash ((hashval_t) gimple_call_internal_fn (fn_from)); else inchash::add_expr (gimple_call_fn (fn_from), hstate); for (i = 0; i < expr->ops.call.nargs; i++) inchash::add_expr (expr->ops.call.args[i], hstate); } break; case EXPR_PHI: { size_t i; for (i = 0; i < expr->ops.phi.nargs; i++) inchash::add_expr (expr->ops.phi.args[i], hstate); } break; default: gcc_unreachable (); } }