// e.g., 3.8.2, 64, arch/x86/ia32/ia32_signal.c copy_siginfo_from_user32(): compat_ptr() u32 max static bool skip_asm_cast(const_tree arg) { gimple def_stmt = get_def_stmt(arg); if (!def_stmt || !gimple_assign_cast_p(def_stmt)) return false; def_stmt = get_def_stmt(gimple_assign_rhs1(def_stmt)); if (is_size_overflow_asm(def_stmt)) return false; return def_stmt && gimple_code(def_stmt) == GIMPLE_ASM; }
static bool process_assignment (gimple stmt, gimple_stmt_iterator call, tree *m, tree *a, tree *ass_var) { tree op0, op1 = NULL_TREE, non_ass_var = NULL_TREE; tree dest = gimple_assign_lhs (stmt); enum tree_code code = gimple_assign_rhs_code (stmt); enum gimple_rhs_class rhs_class = get_gimple_rhs_class (code); tree src_var = gimple_assign_rhs1 (stmt); /* See if this is a simple copy operation of an SSA name to the function result. In that case we may have a simple tail call. Ignore type conversions that can never produce extra code between the function call and the function return. */ if ((rhs_class == GIMPLE_SINGLE_RHS || gimple_assign_cast_p (stmt)) && (TREE_CODE (src_var) == SSA_NAME)) { /* Reject a tailcall if the type conversion might need additional code. */ if (gimple_assign_cast_p (stmt)) { if (TYPE_MODE (TREE_TYPE (dest)) != TYPE_MODE (TREE_TYPE (src_var))) return false; /* Even if the type modes are the same, if the precision of the type is smaller than mode's precision, reduce_to_bit_field_precision would generate additional code. */ if (INTEGRAL_TYPE_P (TREE_TYPE (dest)) && (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (dest))) > TYPE_PRECISION (TREE_TYPE (dest)))) return false; } if (src_var != *ass_var) return false; *ass_var = dest; return true; } switch (rhs_class) { case GIMPLE_BINARY_RHS: op1 = gimple_assign_rhs2 (stmt); /* Fall through. */ case GIMPLE_UNARY_RHS: op0 = gimple_assign_rhs1 (stmt); break; default: return false; } /* Accumulator optimizations will reverse the order of operations. We can only do that for floating-point types if we're assuming that addition and multiplication are associative. */ if (!flag_associative_math) if (FLOAT_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl)))) return false; if (rhs_class == GIMPLE_UNARY_RHS) ; else if (op0 == *ass_var && (non_ass_var = independent_of_stmt_p (op1, stmt, call))) ; else if (op1 == *ass_var && (non_ass_var = independent_of_stmt_p (op0, stmt, call))) ; else return false; switch (code) { case PLUS_EXPR: *a = non_ass_var; *ass_var = dest; return true; case POINTER_PLUS_EXPR: if (op0 != *ass_var) return false; *a = non_ass_var; *ass_var = dest; return true; case MULT_EXPR: *m = non_ass_var; *ass_var = dest; return true; case NEGATE_EXPR: *m = build_minus_one_cst (TREE_TYPE (op0)); *ass_var = dest; return true; case MINUS_EXPR: if (*ass_var == op0) *a = fold_build1 (NEGATE_EXPR, TREE_TYPE (non_ass_var), non_ass_var); else { *m = build_minus_one_cst (TREE_TYPE (non_ass_var)); *a = fold_build1 (NEGATE_EXPR, TREE_TYPE (non_ass_var), non_ass_var); } *ass_var = dest; return true; /* TODO -- Handle POINTER_PLUS_EXPR. */ default: return false; } }
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