static void gen_one_condition (tree arg, int lbub, enum tree_code tcode, const char *temp_name1, const char *temp_name2, vec<gimple> conds, unsigned *nconds) { tree lbub_real_cst, lbub_cst, float_type; tree temp, tempn, tempc, tempcn; gimple stmt1, stmt2, stmt3; float_type = TREE_TYPE (arg); lbub_cst = build_int_cst (integer_type_node, lbub); lbub_real_cst = build_real_from_int_cst (float_type, lbub_cst); temp = create_tmp_var (float_type, temp_name1); stmt1 = gimple_build_assign (temp, arg); tempn = make_ssa_name (temp, stmt1); gimple_assign_set_lhs (stmt1, tempn); tempc = create_tmp_var (boolean_type_node, temp_name2); stmt2 = gimple_build_assign (tempc, fold_build2 (tcode, boolean_type_node, tempn, lbub_real_cst)); tempcn = make_ssa_name (tempc, stmt2); gimple_assign_set_lhs (stmt2, tempcn); stmt3 = gimple_build_cond_from_tree (tempcn, NULL_TREE, NULL_TREE); conds.quick_push (stmt1); conds.quick_push (stmt2); conds.quick_push (stmt3); (*nconds)++; }
void gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base) { tree tmp1; gassign *stmt1, *stmt2, *stmt3; gimple stmt = value->hvalue.stmt; gimple_stmt_iterator gsi = gsi_for_stmt (stmt); tree ref_ptr = tree_coverage_counter_addr (tag, base); if ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) && tag == GCOV_COUNTER_V_INDIR) || (!PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) && tag == GCOV_COUNTER_ICALL_TOPNV)) return; ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, true, NULL_TREE, true, GSI_SAME_STMT); /* Insert code: stmt1: __gcov_indirect_call_counters = get_relevant_counter_ptr (); stmt2: tmp1 = (void *) (indirect call argument value) stmt3: __gcov_indirect_call_callee = tmp1; */ stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr); tmp1 = make_temp_ssa_name (ptr_void, NULL, "PROF"); stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value)); stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2)); gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT); }
static tree adjust_return_value_with_ops (enum tree_code code, const char *label, tree acc, tree op1, gimple_stmt_iterator gsi) { tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl)); tree result = make_temp_ssa_name (ret_type, NULL, label); gassign *stmt; if (POINTER_TYPE_P (ret_type)) { gcc_assert (code == PLUS_EXPR && TREE_TYPE (acc) == sizetype); code = POINTER_PLUS_EXPR; } if (types_compatible_p (TREE_TYPE (acc), TREE_TYPE (op1)) && code != POINTER_PLUS_EXPR) stmt = gimple_build_assign (result, code, acc, op1); else { tree tem; if (code == POINTER_PLUS_EXPR) tem = fold_build2 (code, TREE_TYPE (op1), op1, acc); else tem = fold_build2 (code, TREE_TYPE (op1), fold_convert (TREE_TYPE (op1), acc), op1); tree rhs = fold_convert (ret_type, tem); rhs = force_gimple_operand_gsi (&gsi, rhs, false, NULL, true, GSI_SAME_STMT); stmt = gimple_build_assign (result, rhs); } gsi_insert_before (&gsi, stmt, GSI_NEW_STMT); return result; }
static void mf_decl_cache_locals (void) { gimple g; gimple_seq seq = NULL; /* Build the cache vars. */ mf_cache_shift_decl_l = mf_mark (create_tmp_reg (TREE_TYPE (mf_cache_shift_decl), "__mf_lookup_shift_l")); mf_cache_mask_decl_l = mf_mark (create_tmp_reg (TREE_TYPE (mf_cache_mask_decl), "__mf_lookup_mask_l")); /* Build initialization nodes for the cache vars. We just load the globals into the cache variables. */ g = gimple_build_assign (mf_cache_shift_decl_l, mf_cache_shift_decl); gimple_set_location (g, DECL_SOURCE_LOCATION (current_function_decl)); gimple_seq_add_stmt (&seq, g); g = gimple_build_assign (mf_cache_mask_decl_l, mf_cache_mask_decl); gimple_set_location (g, DECL_SOURCE_LOCATION (current_function_decl)); gimple_seq_add_stmt (&seq, g); insert_edge_copies_seq (seq, ENTRY_BLOCK_PTR); gsi_commit_edge_inserts (); }
static void perturb_latent_entropy(basic_block bb, tree rhs) { gimple_stmt_iterator gsi; gimple assign; tree addxorrol, temp; // 1. create temporary copy of latent_entropy temp = create_tmp_var(unsigned_intDI_type_node, "temp_latent_entropy"); add_referenced_var(temp); // 2. read... temp = make_ssa_name(temp, NULL); assign = gimple_build_assign(temp, latent_entropy_decl); SSA_NAME_DEF_STMT(temp) = assign; add_referenced_var(latent_entropy_decl); gsi = gsi_after_labels(bb); gsi_insert_after(&gsi, assign, GSI_NEW_STMT); update_stmt(assign); // 3. ...modify... addxorrol = fold_build2_loc(UNKNOWN_LOCATION, get_op(NULL), unsigned_intDI_type_node, temp, rhs); temp = make_ssa_name(SSA_NAME_VAR(temp), NULL); assign = gimple_build_assign(temp, addxorrol); SSA_NAME_DEF_STMT(temp) = assign; gsi_insert_after(&gsi, assign, GSI_NEW_STMT); update_stmt(assign); // 4. ...write latent_entropy assign = gimple_build_assign(latent_entropy_decl, temp); gsi_insert_after(&gsi, assign, GSI_NEW_STMT); update_stmt(assign); }
void gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base) { tree tmp1; gimple stmt1, stmt2, stmt3; gimple stmt = value->hvalue.stmt; gimple_stmt_iterator gsi = gsi_for_stmt (stmt); tree ref_ptr = tree_coverage_counter_addr (tag, base); ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, true, NULL_TREE, true, GSI_SAME_STMT); /* Insert code: __gcov_indirect_call_counters = get_relevant_counter_ptr (); __gcov_indirect_call_callee = (void *) indirect call argument; */ tmp1 = create_tmp_reg (ptr_void, "PROF"); stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr); stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value)); gimple_assign_set_lhs (stmt2, make_ssa_name (tmp1, stmt2)); stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2)); gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT); }
bool aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi) { bool changed = false; gimple stmt = gsi_stmt (*gsi); tree call = gimple_call_fn (stmt); tree fndecl; gimple new_stmt = NULL; if (call) { fndecl = gimple_call_fndecl (stmt); if (fndecl) { int fcode = DECL_FUNCTION_CODE (fndecl); int nargs = gimple_call_num_args (stmt); tree *args = (nargs > 0 ? gimple_call_arg_ptr (stmt, 0) : &error_mark_node); /* We use gimple's REDUC_(PLUS|MIN|MAX)_EXPRs for float, signed int and unsigned int; it will distinguish according to the types of the arguments to the __builtin. */ switch (fcode) { BUILTIN_VALL (UNOP, reduc_plus_scal_, 10) new_stmt = gimple_build_assign (gimple_call_lhs (stmt), REDUC_PLUS_EXPR, args[0]); break; BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10) BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10) new_stmt = gimple_build_assign (gimple_call_lhs (stmt), REDUC_MAX_EXPR, args[0]); break; BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10) BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10) new_stmt = gimple_build_assign (gimple_call_lhs (stmt), REDUC_MIN_EXPR, args[0]); break; default: break; } } } if (new_stmt) { gsi_replace (gsi, new_stmt, true); changed = true; } return changed; }
gassign * build_assign (enum tree_code code, tree op1, tree op2, tree lhs) { if (lhs == NULL_TREE) lhs = make_ssa_name (get_expr_type (code, op1)); return gimple_build_assign (lhs, code, op1, op2); }
static void build_arrays (gimple swtch) { tree arr_index_type; tree tidx, sub; gimple stmt; gimple_stmt_iterator gsi; int i; gsi = gsi_for_stmt (swtch); arr_index_type = build_index_type (info.range_size); tidx = make_rename_temp (arr_index_type, "csti"); sub = fold_build2 (MINUS_EXPR, TREE_TYPE (info.index_expr), info.index_expr, fold_convert (TREE_TYPE (info.index_expr), info.range_min)); sub = force_gimple_operand_gsi (&gsi, fold_convert (arr_index_type, sub), false, NULL, true, GSI_SAME_STMT); stmt = gimple_build_assign (tidx, sub); gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); mark_symbols_for_renaming (stmt); info.arr_ref_first = stmt; for (gsi = gsi_start_phis (info.final_bb), i = 0; !gsi_end_p (gsi); gsi_next (&gsi), i++) build_one_array (swtch, i, arr_index_type, gsi_stmt (gsi), tidx); }
tree maybe_push_res_to_seq (code_helper rcode, tree type, tree *ops, gimple_seq *seq, tree res) { if (rcode.is_tree_code ()) { if (!res && (TREE_CODE_LENGTH ((tree_code) rcode) == 0 || ((tree_code) rcode) == ADDR_EXPR) && is_gimple_val (ops[0])) return ops[0]; if (!seq) return NULL_TREE; /* Play safe and do not allow abnormals to be mentioned in newly created statements. */ if ((TREE_CODE (ops[0]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0])) || (ops[1] && TREE_CODE (ops[1]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1])) || (ops[2] && TREE_CODE (ops[2]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2]))) return NULL_TREE; if (!res) res = make_ssa_name (type); maybe_build_generic_op (rcode, type, &ops[0], ops[1], ops[2]); gimple new_stmt = gimple_build_assign (res, rcode, ops[0], ops[1], ops[2]); gimple_seq_add_stmt_without_update (seq, new_stmt); return res; } else { if (!seq) return NULL_TREE; tree decl = builtin_decl_implicit (rcode); if (!decl) return NULL_TREE; unsigned nargs = type_num_arguments (TREE_TYPE (decl)); gcc_assert (nargs <= 3); /* Play safe and do not allow abnormals to be mentioned in newly created statements. */ if ((TREE_CODE (ops[0]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0])) || (nargs >= 2 && TREE_CODE (ops[1]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1])) || (nargs == 3 && TREE_CODE (ops[2]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2]))) return NULL_TREE; if (!res) res = make_ssa_name (type); gimple new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]); gimple_call_set_lhs (new_stmt, res); gimple_seq_add_stmt_without_update (seq, new_stmt); return res; } }
gassign * build_type_cast (tree to_type, tree op, tree lhs) { if (lhs == NULL_TREE) lhs = make_ssa_name (to_type); return gimple_build_assign (lhs, NOP_EXPR, op); }
gassign * build_assign (enum tree_code code, tree op1, int val, tree lhs) { tree op2 = build_int_cst (TREE_TYPE (op1), val); if (lhs == NULL_TREE) lhs = make_ssa_name (get_expr_type (code, op1)); return gimple_build_assign (lhs, code, op1, op2); }
/* * add special KERNEXEC instrumentation: force MSB of fptr to 1, which will produce * a non-canonical address from a userland ptr and will just trigger a GPF on dereference */ static void kernexec_instrument_fptr_bts(gimple_stmt_iterator *gsi) { gimple assign_intptr, assign_new_fptr, call_stmt; tree intptr, orptr, old_fptr, new_fptr, kernexec_mask; call_stmt = gsi_stmt(*gsi); old_fptr = gimple_call_fn(call_stmt); // create temporary unsigned long variable used for bitops and cast fptr to it intptr = create_tmp_var(long_unsigned_type_node, "kernexec_bts"); #if BUILDING_GCC_VERSION <= 4007 add_referenced_var(intptr); #endif intptr = make_ssa_name(intptr, NULL); assign_intptr = gimple_build_assign(intptr, fold_convert(long_unsigned_type_node, old_fptr)); SSA_NAME_DEF_STMT(intptr) = assign_intptr; gsi_insert_before(gsi, assign_intptr, GSI_SAME_STMT); update_stmt(assign_intptr); // apply logical or to temporary unsigned long and bitmask kernexec_mask = build_int_cstu(long_long_unsigned_type_node, 0x8000000000000000LL); // kernexec_mask = build_int_cstu(long_long_unsigned_type_node, 0xffffffff80000000LL); orptr = fold_build2(BIT_IOR_EXPR, long_long_unsigned_type_node, intptr, kernexec_mask); intptr = make_ssa_name(SSA_NAME_VAR(intptr), NULL); assign_intptr = gimple_build_assign(intptr, orptr); SSA_NAME_DEF_STMT(intptr) = assign_intptr; gsi_insert_before(gsi, assign_intptr, GSI_SAME_STMT); update_stmt(assign_intptr); // cast temporary unsigned long back to a temporary fptr variable new_fptr = create_tmp_var(TREE_TYPE(old_fptr), "kernexec_fptr"); #if BUILDING_GCC_VERSION <= 4007 add_referenced_var(new_fptr); #endif new_fptr = make_ssa_name(new_fptr, NULL); assign_new_fptr = gimple_build_assign(new_fptr, fold_convert(TREE_TYPE(old_fptr), intptr)); SSA_NAME_DEF_STMT(new_fptr) = assign_new_fptr; gsi_insert_before(gsi, assign_new_fptr, GSI_SAME_STMT); update_stmt(assign_new_fptr); // replace call stmt fn with the new fptr gimple_call_set_fn(call_stmt, new_fptr); update_stmt(call_stmt); }
void gimple_gen_ic_func_profiler (void) { struct cgraph_node * c_node = cgraph_node::get (current_function_decl); gimple_stmt_iterator gsi; gcall *stmt1; gassign *stmt2; tree tree_uid, cur_func, void0; if (c_node->only_called_directly_p ()) return; gimple_init_edge_profiler (); /* Insert code: stmt1: __gcov_indirect_call_profiler_v2 (profile_id, ¤t_function_decl) */ gsi = gsi_after_labels (split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)))); cur_func = force_gimple_operand_gsi (&gsi, build_addr (current_function_decl, current_function_decl), true, NULL_TREE, true, GSI_SAME_STMT); tree_uid = build_int_cst (gcov_type_node, cgraph_node::get (current_function_decl)->profile_id); /* Workaround for binutils bug 14342. Once it is fixed, remove lto path. */ if (flag_lto) { tree counter_ptr, ptr_var; counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var, true, NULL_TREE, true, GSI_SAME_STMT); ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var, true, NULL_TREE, true, GSI_SAME_STMT); stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4, counter_ptr, tree_uid, cur_func, ptr_var); } else { stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2, tree_uid, cur_func); } gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); /* Set __gcov_indirect_call_callee to 0, so that calls from other modules won't get misattributed to the last caller of the current callee. */ void0 = build_int_cst (build_pointer_type (void_type_node), 0); stmt2 = gimple_build_assign (ic_void_ptr_var, void0); gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); }
void gimple_gen_edge_profiler (int edgeno, edge e) { tree ref, one; gimple stmt1, stmt2, stmt3; /* We share one temporary variable declaration per function. This gets re-set in tree_profiling. */ if (gcov_type_tmp_var == NULL_TREE) gcov_type_tmp_var = create_tmp_reg (gcov_type_node, "PROF_edge_counter"); if (PROFILE_GEN_EDGE_ATOMIC) ref = tree_coverage_counter_addr (GCOV_COUNTER_ARCS, edgeno); else ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); one = build_int_cst (gcov_type_node, 1); if (PROFILE_GEN_EDGE_ATOMIC) { /* __atomic_fetch_add (&counter, 1, MEMMODEL_RELAXED); */ stmt3 = gimple_build_call (builtin_decl_explicit ( GCOV_TYPE_ATOMIC_FETCH_ADD), 3, ref, one, build_int_cst (integer_type_node, MEMMODEL_RELAXED)); find_referenced_vars_in (stmt3); } else { stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); gimple_assign_set_lhs (stmt1, make_ssa_name (gcov_type_tmp_var, stmt1)); find_referenced_vars_in (stmt1); stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, gcov_type_tmp_var, gimple_assign_lhs (stmt1), one); gimple_assign_set_lhs (stmt2, make_ssa_name (gcov_type_tmp_var, stmt2)); stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); gsi_insert_on_edge (e, stmt1); gsi_insert_on_edge (e, stmt2); } gsi_insert_on_edge (e, stmt3); }
void gimple_gen_edge_profiler (int edgeno, edge e) { tree ref, one, gcov_type_tmp_var; gassign *stmt1, *stmt2, *stmt3; ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); one = build_int_cst (gcov_type_node, 1); gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, NULL, "PROF_edge_counter"); stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, NULL, "PROF_edge_counter"); stmt2 = gimple_build_assign (gcov_type_tmp_var, PLUS_EXPR, gimple_assign_lhs (stmt1), one); stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); gsi_insert_on_edge (e, stmt1); gsi_insert_on_edge (e, stmt2); gsi_insert_on_edge (e, stmt3); }
static void lower_builtin_posix_memalign (gimple_stmt_iterator *gsi) { gimple stmt, call = gsi_stmt (*gsi); tree pptr = gimple_call_arg (call, 0); tree align = gimple_call_arg (call, 1); tree res = gimple_call_lhs (call); tree ptr = create_tmp_reg (ptr_type_node, NULL); if (TREE_CODE (pptr) == ADDR_EXPR) { tree tem = create_tmp_var (ptr_type_node, NULL); TREE_ADDRESSABLE (tem) = 1; gimple_call_set_arg (call, 0, build_fold_addr_expr (tem)); stmt = gimple_build_assign (ptr, tem); } else stmt = gimple_build_assign (ptr, fold_build2 (MEM_REF, ptr_type_node, pptr, build_int_cst (ptr_type_node, 0))); if (res == NULL_TREE) { res = create_tmp_reg (integer_type_node, NULL); gimple_call_set_lhs (call, res); } tree align_label = create_artificial_label (UNKNOWN_LOCATION); tree noalign_label = create_artificial_label (UNKNOWN_LOCATION); gimple cond = gimple_build_cond (EQ_EXPR, res, integer_zero_node, align_label, noalign_label); gsi_insert_after (gsi, cond, GSI_NEW_STMT); gsi_insert_after (gsi, gimple_build_label (align_label), GSI_NEW_STMT); gsi_insert_after (gsi, stmt, GSI_NEW_STMT); stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_ASSUME_ALIGNED), 2, ptr, align); gimple_call_set_lhs (stmt, ptr); gsi_insert_after (gsi, stmt, GSI_NEW_STMT); stmt = gimple_build_assign (fold_build2 (MEM_REF, ptr_type_node, pptr, build_int_cst (ptr_type_node, 0)), ptr); gsi_insert_after (gsi, stmt, GSI_NEW_STMT); gsi_insert_after (gsi, gimple_build_label (noalign_label), GSI_NEW_STMT); }
static tree update_accumulator_with_ops (enum tree_code code, tree acc, tree op1, gimple_stmt_iterator gsi) { gassign *stmt; tree var = copy_ssa_name (acc); if (types_compatible_p (TREE_TYPE (acc), TREE_TYPE (op1))) stmt = gimple_build_assign (var, code, acc, op1); else { tree rhs = fold_convert (TREE_TYPE (acc), fold_build2 (code, TREE_TYPE (op1), fold_convert (TREE_TYPE (op1), acc), op1)); rhs = force_gimple_operand_gsi (&gsi, rhs, false, NULL, false, GSI_CONTINUE_LINKING); stmt = gimple_build_assign (var, rhs); } gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); return var; }
void gimple_gen_edge_profiler (int edgeno, edge e) { tree ref, one; gimple stmt1, stmt2, stmt3; /* We share one temporary variable declaration per function. This gets re-set in tree_profiling. */ if (gcov_type_tmp_var == NULL_TREE) gcov_type_tmp_var = create_tmp_reg (gcov_type_node, "PROF_edge_counter"); ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); one = build_int_cst (gcov_type_node, 1); stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); gimple_assign_set_lhs (stmt1, make_ssa_name (gcov_type_tmp_var, stmt1)); stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, gcov_type_tmp_var, gimple_assign_lhs (stmt1), one); gimple_assign_set_lhs (stmt2, make_ssa_name (gcov_type_tmp_var, stmt2)); stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); gsi_insert_on_edge (e, stmt1); gsi_insert_on_edge (e, stmt2); gsi_insert_on_edge (e, stmt3); }
static void perturb_local_entropy(basic_block bb, tree local_entropy) { gimple_stmt_iterator gsi; gimple assign; tree addxorrol, rhs; enum tree_code op; op = get_op(&rhs); addxorrol = fold_build2_loc(UNKNOWN_LOCATION, op, unsigned_intDI_type_node, local_entropy, rhs); assign = gimple_build_assign(local_entropy, addxorrol); gsi = gsi_after_labels(bb); gsi_insert_before(&gsi, assign, GSI_NEW_STMT); update_stmt(assign); //debug_bb(bb); }
void gimple_gen_ic_func_profiler (void) { struct cgraph_node * c_node = cgraph_get_node (current_function_decl); gimple_stmt_iterator gsi; gimple stmt1, stmt2; tree tree_uid, cur_func, counter_ptr, ptr_var, void0; if (cgraph_only_called_directly_p (c_node)) return; gimple_init_edge_profiler (); /* Insert code: stmt1: __gcov_indirect_call_profiler (__gcov_indirect_call_counters, current_function_funcdef_no, ¤t_function_decl, __gcov_indirect_call_callee); */ gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR)); cur_func = force_gimple_operand_gsi (&gsi, build_addr (current_function_decl, current_function_decl), true, NULL_TREE, true, GSI_SAME_STMT); counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var, true, NULL_TREE, true, GSI_SAME_STMT); ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var, true, NULL_TREE, true, GSI_SAME_STMT); tree_uid = build_int_cst (gcov_type_node, current_function_funcdef_no); stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4, counter_ptr, tree_uid, cur_func, ptr_var); gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); /* Set __gcov_indirect_call_callee to 0, so that calls from other modules won't get misattributed to the last caller of the current callee. */ void0 = build_int_cst (build_pointer_type (void_type_node), 0); stmt2 = gimple_build_assign (ic_void_ptr_var, void0); gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); }
static gimple gen_def_assigns (gimple_stmt_iterator *gsi) { int i; gimple assign = NULL; for (i = 0; i < info.phi_count; i++) { tree name = make_ssa_name (SSA_NAME_VAR (info.target_inbound_names[i]), NULL); info.target_outbound_names[i] = name; assign = gimple_build_assign (name, info.default_values[i]); SSA_NAME_DEF_STMT (name) = assign; gsi_insert_before (gsi, assign, GSI_SAME_STMT); find_new_referenced_vars (assign); mark_symbols_for_renaming (assign); } return assign; }
static void build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi, tree tidx) { tree array_type, ctor, decl, value_type, name, fetch; gimple load; gimple_stmt_iterator gsi; gcc_assert (info.default_values[num]); value_type = TREE_TYPE (info.default_values[num]); array_type = build_array_type (value_type, arr_index_type); ctor = build_constructor (array_type, info.constructors[num]); TREE_CONSTANT (ctor) = true; decl = build_decl (VAR_DECL, NULL_TREE, array_type); TREE_STATIC (decl) = 1; DECL_INITIAL (decl) = ctor; DECL_NAME (decl) = create_tmp_var_name ("CSWTCH"); DECL_ARTIFICIAL (decl) = 1; TREE_CONSTANT (decl) = 1; add_referenced_var (decl); varpool_mark_needed_node (varpool_node (decl)); varpool_finalize_decl (decl); mark_sym_for_renaming (decl); name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL); info.target_inbound_names[num] = name; fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE, NULL_TREE); load = gimple_build_assign (name, fetch); SSA_NAME_DEF_STMT (name) = load; gsi = gsi_for_stmt (swtch); gsi_insert_before (&gsi, load, GSI_SAME_STMT); mark_symbols_for_renaming (load); info.arr_ref_last = load; }
void propagate_tree_value_into_stmt (gimple_stmt_iterator *gsi, tree val) { gimple stmt = gsi_stmt (*gsi); if (is_gimple_assign (stmt)) { tree expr = NULL_TREE; if (gimple_assign_single_p (stmt)) expr = gimple_assign_rhs1 (stmt); propagate_tree_value (&expr, val); gimple_assign_set_rhs_from_tree (gsi, expr); stmt = gsi_stmt (*gsi); } else if (gimple_code (stmt) == GIMPLE_COND) { tree lhs = NULL_TREE; tree rhs = fold_convert (TREE_TYPE (val), integer_zero_node); propagate_tree_value (&lhs, val); gimple_cond_set_code (stmt, NE_EXPR); gimple_cond_set_lhs (stmt, lhs); gimple_cond_set_rhs (stmt, rhs); } else if (is_gimple_call (stmt) && gimple_call_lhs (stmt) != NULL_TREE) { gimple new_stmt; tree expr = NULL_TREE; propagate_tree_value (&expr, val); new_stmt = gimple_build_assign (gimple_call_lhs (stmt), expr); copy_virtual_operands (new_stmt, stmt); move_ssa_defining_stmt_for_defs (new_stmt, stmt); gsi_replace (gsi, new_stmt, false); } else if (gimple_code (stmt) == GIMPLE_SWITCH) propagate_tree_value (gimple_switch_index_ptr (stmt), val); else gcc_unreachable (); }
static void mf_build_check_statement_for (tree base, tree limit, gimple_stmt_iterator *instr_gsi, location_t location, tree dirflag) { gimple_stmt_iterator gsi; basic_block cond_bb, then_bb, join_bb; edge e; tree cond, t, u, v; tree mf_base; tree mf_elem; tree mf_limit; gimple g; gimple_seq seq, stmts; /* We first need to split the current basic block, and start altering the CFG. This allows us to insert the statements we're about to construct into the right basic blocks. */ cond_bb = gimple_bb (gsi_stmt (*instr_gsi)); gsi = *instr_gsi; gsi_prev (&gsi); if (! gsi_end_p (gsi)) e = split_block (cond_bb, gsi_stmt (gsi)); else e = split_block_after_labels (cond_bb); cond_bb = e->src; join_bb = e->dest; /* A recap at this point: join_bb is the basic block at whose head is the gimple statement for which this check expression is being built. cond_bb is the (possibly new, synthetic) basic block the end of which will contain the cache-lookup code, and a conditional that jumps to the cache-miss code or, much more likely, over to join_bb. */ /* Create the bb that contains the cache-miss fallback block (mf_check). */ then_bb = create_empty_bb (cond_bb); make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE); make_single_succ_edge (then_bb, join_bb, EDGE_FALLTHRU); /* Mark the pseudo-fallthrough edge from cond_bb to join_bb. */ e = find_edge (cond_bb, join_bb); e->flags = EDGE_FALSE_VALUE; e->count = cond_bb->count; e->probability = REG_BR_PROB_BASE; /* Update dominance info. Note that bb_join's data was updated by split_block. */ if (dom_info_available_p (CDI_DOMINATORS)) { set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb); set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb); } /* Update loop info. */ if (current_loops) add_bb_to_loop (then_bb, cond_bb->loop_father); /* Build our local variables. */ mf_elem = create_tmp_reg (mf_cache_structptr_type, "__mf_elem"); mf_base = create_tmp_reg (mf_uintptr_type, "__mf_base"); mf_limit = create_tmp_reg (mf_uintptr_type, "__mf_limit"); /* Build: __mf_base = (uintptr_t) <base address expression>. */ seq = NULL; t = fold_convert_loc (location, mf_uintptr_type, unshare_expr (base)); t = force_gimple_operand (t, &stmts, false, NULL_TREE); gimple_seq_add_seq (&seq, stmts); g = gimple_build_assign (mf_base, t); gimple_set_location (g, location); gimple_seq_add_stmt (&seq, g); /* Build: __mf_limit = (uintptr_t) <limit address expression>. */ t = fold_convert_loc (location, mf_uintptr_type, unshare_expr (limit)); t = force_gimple_operand (t, &stmts, false, NULL_TREE); gimple_seq_add_seq (&seq, stmts); g = gimple_build_assign (mf_limit, t); gimple_set_location (g, location); gimple_seq_add_stmt (&seq, g); /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift) & __mf_mask]. */ t = build2 (RSHIFT_EXPR, mf_uintptr_type, mf_base, flag_mudflap_threads ? mf_cache_shift_decl : mf_cache_shift_decl_l); t = build2 (BIT_AND_EXPR, mf_uintptr_type, t, flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l); t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (mf_cache_array_decl)), mf_cache_array_decl, t, NULL_TREE, NULL_TREE); t = build1 (ADDR_EXPR, mf_cache_structptr_type, t); t = force_gimple_operand (t, &stmts, false, NULL_TREE); gimple_seq_add_seq (&seq, stmts); g = gimple_build_assign (mf_elem, t); gimple_set_location (g, location); gimple_seq_add_stmt (&seq, g); /* Quick validity check. if (__mf_elem->low > __mf_base || (__mf_elem_high < __mf_limit)) { __mf_check (); ... and only if single-threaded: __mf_lookup_shift_1 = f...; __mf_lookup_mask_l = ...; } It is expected that this body of code is rarely executed so we mark the edge to the THEN clause of the conditional jump as unlikely. */ /* Construct t <-- '__mf_elem->low > __mf_base'. */ t = build3 (COMPONENT_REF, mf_uintptr_type, build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem), TYPE_FIELDS (mf_cache_struct_type), NULL_TREE); t = build2 (GT_EXPR, boolean_type_node, t, mf_base); /* Construct '__mf_elem->high < __mf_limit'. First build: 1) u <-- '__mf_elem->high' 2) v <-- '__mf_limit'. Then build 'u <-- (u < v). */ u = build3 (COMPONENT_REF, mf_uintptr_type, build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem), DECL_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE); v = mf_limit; u = build2 (LT_EXPR, boolean_type_node, u, v); /* Build the composed conditional: t <-- 't || u'. Then store the result of the evaluation of 't' in a temporary variable which we can use as the condition for the conditional jump. */ t = build2 (TRUTH_OR_EXPR, boolean_type_node, t, u); t = force_gimple_operand (t, &stmts, false, NULL_TREE); gimple_seq_add_seq (&seq, stmts); cond = create_tmp_reg (boolean_type_node, "__mf_unlikely_cond"); g = gimple_build_assign (cond, t); gimple_set_location (g, location); gimple_seq_add_stmt (&seq, g); /* Build the conditional jump. 'cond' is just a temporary so we can simply build a void COND_EXPR. We do need labels in both arms though. */ g = gimple_build_cond (NE_EXPR, cond, boolean_false_node, NULL_TREE, NULL_TREE); gimple_set_location (g, location); gimple_seq_add_stmt (&seq, g); /* At this point, after so much hard work, we have only constructed the conditional jump, if (__mf_elem->low > __mf_base || (__mf_elem_high < __mf_limit)) The lowered GIMPLE tree representing this code is in the statement list starting at 'head'. We can insert this now in the current basic block, i.e. the one that the statement we're instrumenting was originally in. */ gsi = gsi_last_bb (cond_bb); gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING); /* Now build up the body of the cache-miss handling: __mf_check(); refresh *_l vars. This is the body of the conditional. */ seq = NULL; /* u is a string, so it is already a gimple value. */ u = mf_file_function_line_tree (location); /* NB: we pass the overall [base..limit] range to mf_check. */ v = fold_build2_loc (location, PLUS_EXPR, mf_uintptr_type, fold_build2_loc (location, MINUS_EXPR, mf_uintptr_type, mf_limit, mf_base), build_int_cst (mf_uintptr_type, 1)); v = force_gimple_operand (v, &stmts, true, NULL_TREE); gimple_seq_add_seq (&seq, stmts); g = gimple_build_call (mf_check_fndecl, 4, mf_base, v, dirflag, u); gimple_seq_add_stmt (&seq, g); if (! flag_mudflap_threads) { if (stmt_ends_bb_p (g)) { gsi = gsi_start_bb (then_bb); gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING); e = split_block (then_bb, g); then_bb = e->dest; seq = NULL; } g = gimple_build_assign (mf_cache_shift_decl_l, mf_cache_shift_decl); gimple_seq_add_stmt (&seq, g); g = gimple_build_assign (mf_cache_mask_decl_l, mf_cache_mask_decl); gimple_seq_add_stmt (&seq, g); } /* Insert the check code in the THEN block. */ gsi = gsi_start_bb (then_bb); gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING); *instr_gsi = gsi_start_bb (join_bb); }
enum tree_code tcode, const char *temp_name1, const char *temp_name2, VEC (gimple, heap) *conds, unsigned *nconds) { tree lbub_real_cst, lbub_cst, float_type; tree temp, tempn, tempc, tempcn; gimple stmt1, stmt2, stmt3; float_type = TREE_TYPE (arg); lbub_cst = build_int_cst (integer_type_node, lbub); lbub_real_cst = build_real_from_int_cst (float_type, lbub_cst); temp = create_tmp_var (float_type, temp_name1); stmt1 = gimple_build_assign (temp, arg); tempn = make_ssa_name (temp, stmt1); gimple_assign_set_lhs (stmt1, tempn); tempc = create_tmp_var (boolean_type_node, temp_name2); stmt2 = gimple_build_assign (tempc, fold_build2 (tcode, boolean_type_node, tempn, lbub_real_cst)); tempcn = make_ssa_name (tempc, stmt2); gimple_assign_set_lhs (stmt2, tempcn); stmt3 = gimple_build_cond_from_tree (tempcn, NULL_TREE, NULL_TREE); VEC_quick_push (gimple, conds, stmt1); VEC_quick_push (gimple, conds, stmt2); VEC_quick_push (gimple, conds, stmt3);
static void my_dump_gimple(gimple gnode, gimple_stmt_iterator *ptrgsi) { int gcode; tree tnode; tree funcdecl; tree desc_node; tree ptr_desc_node; tree t; tree tmp_var; tree const_char_restrict_ptr_type_node; gimple tmp_gstmt; gimple new_gnode; const char *hellocstr = "Hello, GCC!\n"; int i; struct c_binding *b; expanded_location xloc; /* * Extract the Gimple Code from a gimple node */ gcode = gimple_code(gnode); /* * Get the line number of cooresponding * source code from a gimple node */ if(gimple_has_location(gnode)) { xloc = expand_location(gimple_location(gnode)); printf("line %d:", xloc.line); } printf("\t\t\t\t%s\n", gimple_code_name[gcode]); switch(gcode) { case GIMPLE_ASSIGN: /* * Add a printf("Hello, GCC!\n"); statement * after the first appearing assignment * if yes equals to 1, then we have already * added the statement, and no need to add * again */ if(!yes) { /* * Since printf is a builtin function, we need * to get the function declaration using * built_in_decls[]. The index number can be * found in gcc source gcc/builtins.def */ funcdecl = built_in_decls[BUILT_IN_PRINTF]; if(funcdecl == NULL_TREE) { printf("cannot find printf\n"); } else { /* * In gimple, every statement is simplified into * three oprands mode. And our printf() statement * is change into following two gimple statements: * * <D.XXX> = (const char * restrict) &"Hello, GCC!\n"[0] * printf(<D.XXX>); * * Note that <D.XXX> is a temporary variable, we can * actually use any name we like as long as no * confliction. */ /* * Generate a STRING_CST, the value is "Hello, GCC!\n" */ desc_node = build_string(strlen(hellocstr), hellocstr); /* * Two points need to notice here: * 1. STRING_CST build by build_string() do * not have TREE_TYPE set, so we need to * set it manually. * 2. build_string() will add a trailing '\0' * when building the STRING_CST, so we do * not need to care with it. */ TREE_TYPE(desc_node) = build_array_type( char_type_node, build_index_type( build_int_cst(NULL_TREE, strlen(hellocstr)))); /* * Define a const char * restrict type node * here for convertion. * I'm not sure why we need to add a restrict * attribute, but GCC really does it when it * converting a STRING_CST from AST to Gimple. */ const_char_restrict_ptr_type_node = build_qualified_type( build_pointer_type( build_qualified_type( char_type_node, TYPE_QUAL_CONST)), TYPE_QUAL_RESTRICT); /* * When we in AST, if we want to use STRING_CST * the form is like this <ADDR_EXPR<STRING_CST>>, * but when we turn to gimple, it is like this * <ADDR_EXPR<ADDAR_REF<STRING_CST>>>. * So we need to do a convertion there. */ /* * First wrap STRING_CST with ARRAY_REF */ t = build4(ARRAY_REF, char_type_node, desc_node, build_int_cst(NULL_TREE, 0), NULL, NULL); /* * Second wrap ARRAY_REF with ADDR_EXPR */ ptr_desc_node = build1(ADDR_EXPR, const_char_restrict_ptr_type_node, t); /* * I'm not sure why we need to use fold_convert() * here, but if we do not, we cannot make the * compiling successful. */ ptr_desc_node = fold_convert( const_char_restrict_ptr_type_node, ptr_desc_node); /* * If is_gimple_min_invariant(ptr_desc_node) * is true, we build a corrent argument, otherwise * the argument is not suitable for gimple call */ if(!is_gimple_min_invariant(ptr_desc_node)) { printf("Something wrong with is_gimple_min_invariant\n"); return ; } /* * This applies for a temporary variable */ tmp_var = make_rename_temp( const_char_restrict_ptr_type_node, "plugin_var"); /* * Build a gimple statement. Still remember that? * <D.XXX> = (const char * restrict) "Hello, GCC!\n" */ tmp_gstmt = gimple_build_assign(tmp_var, ptr_desc_node); /* * Check if the gimple statment is corrent */ if(!is_gimple_assign(tmp_gstmt)) { printf("tmp_gstmt is invalid\n"); } printf("Insert gimple statment:"); print_gimple_stmt(stdout, tmp_gstmt, 0, TDF_DETAILS | TDF_VERBOSE | TDF_TREE); /* * Insert the gimple statment into the basic block */ gsi_insert_after(ptrgsi, tmp_gstmt, GSI_NEW_STMT); if(is_gimple_operand(tmp_var)) { printf("begin to insert printf\n"); yes = 1; printf("Insert gimple statment:"); /* * Insert the gimple statment printf * into the basic block */ new_gnode = gimple_build_call( funcdecl, 1, tmp_var); print_gimple_stmt(stdout, new_gnode, 0, 0); gsi_insert_after(ptrgsi, new_gnode, GSI_NEW_STMT); } else { print_generic_stmt(stdout, ptr_desc_node, TDF_DETAILS | TDF_VERBOSE | TDF_TREE); printf("Not Gimple Operands\n"); } /* * Since we have more than one consecutive statements * to insert, we can actually use build a gimple * sequence, insert all statement into the sequence, * and then insert the sequence into the basic block. * This seems to be a better method. */ } } else { } break; default: break; } }
if (e && single_pred_p (e->dest)) continue; set_immediate_dominator (CDI_DOMINATORS, dom_son, switch_bb); bbs_to_fix_dom.safe_push (dom_son); } dom_bbs.release (); } /* csui = (1 << (word_mode) idx) */ csui = make_ssa_name (word_type_node); tmp = fold_build2 (LSHIFT_EXPR, word_type_node, word_mode_one, fold_convert (word_type_node, idx)); tmp = force_gimple_operand_gsi (&gsi, tmp, /*simple=*/false, NULL_TREE, /*before=*/true, GSI_SAME_STMT); shift_stmt = gimple_build_assign (csui, tmp); gsi_insert_before (&gsi, shift_stmt, GSI_SAME_STMT); update_stmt (shift_stmt); /* for each unique set of cases: if (const & csui) goto target */ for (k = 0; k < count; k++) { tmp = wide_int_to_tree (word_type_node, test[k].mask); tmp = fold_build2 (BIT_AND_EXPR, word_type_node, csui, tmp); tmp = force_gimple_operand_gsi (&gsi, tmp, /*simple=*/true, NULL_TREE, /*before=*/true, GSI_SAME_STMT); tmp = fold_build2 (NE_EXPR, boolean_type_node, tmp, word_mode_zero); new_bb = hoist_edge_and_branch_if_true (&gsi, tmp, test[k].target_edge, update_dom);
void gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p) { size_t i, num_ops; tree lhs; gimple_seq pre = NULL; gimple post_stmt = NULL; push_gimplify_context (gimple_in_ssa_p (cfun)); switch (gimple_code (stmt)) { case GIMPLE_COND: gimplify_expr (gimple_cond_lhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); gimplify_expr (gimple_cond_rhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; case GIMPLE_SWITCH: gimplify_expr (gimple_switch_index_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; case GIMPLE_OMP_ATOMIC_LOAD: gimplify_expr (gimple_omp_atomic_load_rhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; case GIMPLE_ASM: { size_t i, noutputs = gimple_asm_noutputs (stmt); const char *constraint, **oconstraints; bool allows_mem, allows_reg, is_inout; oconstraints = (const char **) alloca ((noutputs) * sizeof (const char *)); for (i = 0; i < noutputs; i++) { tree op = gimple_asm_output_op (stmt, i); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); oconstraints[i] = constraint; parse_output_constraint (&constraint, i, 0, 0, &allows_mem, &allows_reg, &is_inout); gimplify_expr (&TREE_VALUE (op), &pre, NULL, is_inout ? is_gimple_min_lval : is_gimple_lvalue, fb_lvalue | fb_mayfail); } for (i = 0; i < gimple_asm_ninputs (stmt); i++) { tree op = gimple_asm_input_op (stmt, i); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints, &allows_mem, &allows_reg); if (TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (op))) && allows_mem) allows_reg = 0; if (!allows_reg && allows_mem) gimplify_expr (&TREE_VALUE (op), &pre, NULL, is_gimple_lvalue, fb_lvalue | fb_mayfail); else gimplify_expr (&TREE_VALUE (op), &pre, NULL, is_gimple_asm_val, fb_rvalue); } } break; default: /* NOTE: We start gimplifying operands from last to first to make sure that side-effects on the RHS of calls, assignments and ASMs are executed before the LHS. The ordering is not important for other statements. */ num_ops = gimple_num_ops (stmt); for (i = num_ops; i > 0; i--) { tree op = gimple_op (stmt, i - 1); if (op == NULL_TREE) continue; if (i == 1 && (is_gimple_call (stmt) || is_gimple_assign (stmt))) gimplify_expr (&op, &pre, NULL, is_gimple_lvalue, fb_lvalue); else if (i == 2 && is_gimple_assign (stmt) && num_ops == 2 && get_gimple_rhs_class (gimple_expr_code (stmt)) == GIMPLE_SINGLE_RHS) gimplify_expr (&op, &pre, NULL, rhs_predicate_for (gimple_assign_lhs (stmt)), fb_rvalue); else if (i == 2 && is_gimple_call (stmt)) { if (TREE_CODE (op) == FUNCTION_DECL) continue; gimplify_expr (&op, &pre, NULL, is_gimple_call_addr, fb_rvalue); } else gimplify_expr (&op, &pre, NULL, is_gimple_val, fb_rvalue); gimple_set_op (stmt, i - 1, op); } lhs = gimple_get_lhs (stmt); /* If the LHS changed it in a way that requires a simple RHS, create temporary. */ if (lhs && !is_gimple_reg (lhs)) { bool need_temp = false; if (is_gimple_assign (stmt) && num_ops == 2 && get_gimple_rhs_class (gimple_expr_code (stmt)) == GIMPLE_SINGLE_RHS) gimplify_expr (gimple_assign_rhs1_ptr (stmt), &pre, NULL, rhs_predicate_for (gimple_assign_lhs (stmt)), fb_rvalue); else if (is_gimple_reg (lhs)) { if (is_gimple_reg_type (TREE_TYPE (lhs))) { if (is_gimple_call (stmt)) { i = gimple_call_flags (stmt); if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE))) need_temp = true; } if (stmt_can_throw_internal (stmt)) need_temp = true; } } else { if (is_gimple_reg_type (TREE_TYPE (lhs))) need_temp = true; else if (TYPE_MODE (TREE_TYPE (lhs)) != BLKmode) { if (is_gimple_call (stmt)) { tree fndecl = gimple_call_fndecl (stmt); if (!aggregate_value_p (TREE_TYPE (lhs), fndecl) && !(fndecl && DECL_RESULT (fndecl) && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))) need_temp = true; } else need_temp = true; } } if (need_temp) { tree temp = create_tmp_reg (TREE_TYPE (lhs), NULL); if (gimple_in_ssa_p (cfun)) temp = make_ssa_name (temp, NULL); gimple_set_lhs (stmt, temp); post_stmt = gimple_build_assign (lhs, temp); } } break; } if (!gimple_seq_empty_p (pre)) gsi_insert_seq_before (gsi_p, pre, GSI_SAME_STMT); if (post_stmt) gsi_insert_after (gsi_p, post_stmt, GSI_NEW_STMT); pop_gimplify_context (NULL); }
tree maybe_push_res_to_seq (code_helper rcode, tree type, tree *ops, gimple_seq *seq, tree res) { if (rcode.is_tree_code ()) { if (!res && gimple_simplified_result_is_gimple_val (rcode, ops)) return ops[0]; if (mprts_hook) { tree tem = mprts_hook (rcode, type, ops); if (tem) return tem; } if (!seq) return NULL_TREE; /* Play safe and do not allow abnormals to be mentioned in newly created statements. */ if ((TREE_CODE (ops[0]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0])) || (ops[1] && TREE_CODE (ops[1]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1])) || (ops[2] && TREE_CODE (ops[2]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2]))) return NULL_TREE; if (!res) res = make_ssa_name (type); maybe_build_generic_op (rcode, type, &ops[0], ops[1], ops[2]); gimple *new_stmt = gimple_build_assign (res, rcode, ops[0], ops[1], ops[2]); gimple_seq_add_stmt_without_update (seq, new_stmt); return res; } else { if (!seq) return NULL_TREE; tree decl = builtin_decl_implicit (rcode); if (!decl) return NULL_TREE; /* We can't and should not emit calls to non-const functions. */ if (!(flags_from_decl_or_type (decl) & ECF_CONST)) return NULL_TREE; /* Play safe and do not allow abnormals to be mentioned in newly created statements. */ unsigned nargs; for (nargs = 0; nargs < 3; ++nargs) { if (!ops[nargs]) break; if (TREE_CODE (ops[nargs]) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[nargs])) return NULL_TREE; } gcc_assert (nargs != 0); if (!res) res = make_ssa_name (type); gimple *new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]); gimple_call_set_lhs (new_stmt, res); gimple_seq_add_stmt_without_update (seq, new_stmt); return res; } }