- case GIMPLE_ASSIGN:
- {
- enum tree_code subcode = gimple_assign_rhs_code (stmt);
-
- switch (get_gimple_rhs_class (subcode))
- {
- case GIMPLE_SINGLE_RHS:
- {
- tree rhs = gimple_assign_rhs1 (stmt);
- enum tree_code_class kind = TREE_CODE_CLASS (subcode);
-
- if (TREE_CODE (rhs) == SSA_NAME)
- {
- /* If the RHS is an SSA_NAME, return its known constant value,
- if any. */
- return get_value (rhs)->value;
- }
- /* Handle propagating invariant addresses into address operations.
- The folding we do here matches that in tree-ssa-forwprop.c. */
- else if (TREE_CODE (rhs) == ADDR_EXPR)
- {
- tree *base;
- base = &TREE_OPERAND (rhs, 0);
- while (handled_component_p (*base))
- base = &TREE_OPERAND (*base, 0);
- if (TREE_CODE (*base) == INDIRECT_REF
- && TREE_CODE (TREE_OPERAND (*base, 0)) == SSA_NAME)
- {
- prop_value_t *val = get_value (TREE_OPERAND (*base, 0));
- if (val->lattice_val == CONSTANT
- && TREE_CODE (val->value) == ADDR_EXPR
- && may_propagate_address_into_dereference
- (val->value, *base))
- {
- /* We need to return a new tree, not modify the IL
- or share parts of it. So play some tricks to
- avoid manually building it. */
- tree ret, save = *base;
- *base = TREE_OPERAND (val->value, 0);
- ret = unshare_expr (rhs);
- recompute_tree_invariant_for_addr_expr (ret);
- *base = save;
- return ret;
- }
- }
- }
-
- if (kind == tcc_reference)
- {
- if ((TREE_CODE (rhs) == VIEW_CONVERT_EXPR
- || TREE_CODE (rhs) == REALPART_EXPR
- || TREE_CODE (rhs) == IMAGPART_EXPR)
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
- {
- prop_value_t *val = get_value (TREE_OPERAND (rhs, 0));
- if (val->lattice_val == CONSTANT)
- return fold_unary (TREE_CODE (rhs),
- TREE_TYPE (rhs), val->value);
- }
- else if (TREE_CODE (rhs) == INDIRECT_REF
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
- {
- prop_value_t *val = get_value (TREE_OPERAND (rhs, 0));
- if (val->lattice_val == CONSTANT
- && TREE_CODE (val->value) == ADDR_EXPR
- && useless_type_conversion_p (TREE_TYPE (rhs),
- TREE_TYPE (TREE_TYPE (val->value))))
- rhs = TREE_OPERAND (val->value, 0);
- }
- return fold_const_aggregate_ref (rhs);
- }
- else if (kind == tcc_declaration)
- return get_symbol_constant_value (rhs);
- return rhs;
- }
-
- case GIMPLE_UNARY_RHS:
- {
- /* Handle unary operators that can appear in GIMPLE form.
- Note that we know the single operand must be a constant,
- so this should almost always return a simplified RHS. */
- tree lhs = gimple_assign_lhs (stmt);
- tree op0 = gimple_assign_rhs1 (stmt);
-
- /* Simplify the operand down to a constant. */
- if (TREE_CODE (op0) == SSA_NAME)
- {
- prop_value_t *val = get_value (op0);
- if (val->lattice_val == CONSTANT)
- op0 = get_value (op0)->value;
- }
-
- /* Conversions are useless for CCP purposes if they are
- value-preserving. Thus the restrictions that
- useless_type_conversion_p places for pointer type conversions
- do not apply here. Substitution later will only substitute to
- allowed places. */
- if (CONVERT_EXPR_CODE_P (subcode)
- && POINTER_TYPE_P (TREE_TYPE (lhs))
- && POINTER_TYPE_P (TREE_TYPE (op0))
- /* Do not allow differences in volatile qualification
- as this might get us confused as to whether a
- propagation destination statement is volatile
- or not. See PR36988. */
- && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (lhs)))
- == TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op0)))))
- {
- tree tem;
- /* Still try to generate a constant of correct type. */
- if (!useless_type_conversion_p (TREE_TYPE (lhs),
- TREE_TYPE (op0))
- && ((tem = maybe_fold_offset_to_address
- (op0, integer_zero_node, TREE_TYPE (lhs)))
- != NULL_TREE))
- return tem;
- return op0;
- }
-
- return fold_unary_ignore_overflow (subcode,
- gimple_expr_type (stmt), op0);
- }
-
- case GIMPLE_BINARY_RHS:
- {
- /* Handle binary operators that can appear in GIMPLE form. */
- tree op0 = gimple_assign_rhs1 (stmt);
- tree op1 = gimple_assign_rhs2 (stmt);
-
- /* Simplify the operands down to constants when appropriate. */
- if (TREE_CODE (op0) == SSA_NAME)
- {
- prop_value_t *val = get_value (op0);
- if (val->lattice_val == CONSTANT)
- op0 = val->value;
- }
-
- if (TREE_CODE (op1) == SSA_NAME)
- {
- prop_value_t *val = get_value (op1);
- if (val->lattice_val == CONSTANT)
- op1 = val->value;
- }
-
- /* Fold &foo + CST into an invariant reference if possible. */
- if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
- && TREE_CODE (op0) == ADDR_EXPR
- && TREE_CODE (op1) == INTEGER_CST)
- {
- tree lhs = gimple_assign_lhs (stmt);
- tree tem = maybe_fold_offset_to_address (op0, op1,
- TREE_TYPE (lhs));
- if (tem != NULL_TREE)
- return tem;
- }
-
- return fold_binary (subcode, gimple_expr_type (stmt), op0, op1);
- }
-
- default:
- gcc_unreachable ();
- }
- }
- break;
-
- case GIMPLE_CALL:
- {
- tree fn = gimple_call_fn (stmt);
- prop_value_t *val;
-
- if (TREE_CODE (fn) == SSA_NAME)
- {
- val = get_value (fn);
- if (val->lattice_val == CONSTANT)
- fn = val->value;
- }
- if (TREE_CODE (fn) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
- && DECL_BUILT_IN (TREE_OPERAND (fn, 0)))
- {
- tree *args = XALLOCAVEC (tree, gimple_call_num_args (stmt));
- tree call, retval;
- unsigned i;
- for (i = 0; i < gimple_call_num_args (stmt); ++i)
- {
- args[i] = gimple_call_arg (stmt, i);
- if (TREE_CODE (args[i]) == SSA_NAME)
- {
- val = get_value (args[i]);
- if (val->lattice_val == CONSTANT)
- args[i] = val->value;
- }
- }
- call = build_call_array (gimple_call_return_type (stmt),
- fn, gimple_call_num_args (stmt), args);
- retval = fold_call_expr (call, false);
- if (retval)
- /* fold_call_expr wraps the result inside a NOP_EXPR. */
- STRIP_NOPS (retval);
- return retval;
- }
- return NULL_TREE;
- }
-