static void instrument_si_overflow (gimple_stmt_iterator gsi) { gimple stmt = gsi_stmt (gsi); tree_code code = gimple_assign_rhs_code (stmt); tree lhs = gimple_assign_lhs (stmt); tree lhstype = TREE_TYPE (lhs); tree a, b; gimple g; /* If this is not a signed operation, don't instrument anything here. Also punt on bit-fields. */ if (!INTEGRAL_TYPE_P (lhstype) || TYPE_OVERFLOW_WRAPS (lhstype) || GET_MODE_BITSIZE (TYPE_MODE (lhstype)) != TYPE_PRECISION (lhstype)) return; switch (code) { case MINUS_EXPR: case PLUS_EXPR: case MULT_EXPR: /* Transform i = u {+,-,*} 5; into i = UBSAN_CHECK_{ADD,SUB,MUL} (u, 5); */ a = gimple_assign_rhs1 (stmt); b = gimple_assign_rhs2 (stmt); g = gimple_build_call_internal (code == PLUS_EXPR ? IFN_UBSAN_CHECK_ADD : code == MINUS_EXPR ? IFN_UBSAN_CHECK_SUB : IFN_UBSAN_CHECK_MUL, 2, a, b); gimple_call_set_lhs (g, lhs); gsi_replace (&gsi, g, false); break; case NEGATE_EXPR: /* Represent i = -u; as i = UBSAN_CHECK_SUB (0, u); */ a = build_int_cst (lhstype, 0); b = gimple_assign_rhs1 (stmt); g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b); gimple_call_set_lhs (g, lhs); gsi_replace (&gsi, g, false); break; default: break; } }
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; }
void gsi_replace_with_seq (gimple_stmt_iterator *gsi, gimple_seq seq, bool update_eh_info) { gimple_stmt_iterator seqi; gimple *last; if (gimple_seq_empty_p (seq)) { gsi_remove (gsi, true); return; } seqi = gsi_last (seq); last = gsi_stmt (seqi); gsi_remove (&seqi, false); gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT); gsi_replace (gsi, last, update_eh_info); }
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 handle_task_call (gimple_stmt_iterator gsi, const tracked_func_t* tf) { /* iterator points to the call instruction */ /* . generate the following statement list: generate type T; declare T* var; var = call __xkaapi_pushdata(sizeof(T)); foreach args, var->member = local_value; call __xkaapi_pushtask(); call __xkaapi_barrier(); */ tree dummy_adapter; tree sp; tree thread; gimple_seq stmts; gimple call; init_decls(); /* kaapi_pushdata_aligned */ gen_alloca_stmts(&stmts, &sp); gsi_insert_seq_before(&gsi, stmts, GSI_SAME_STMT); /* fixme: gimple_seq_free(alloca_stmts); */ /* generate the adapter routine */ /* dummy_adapter = create_dummy_adapter(); */ /* kaapi_pushtask(self_thread, sp); */ thread = build_int_cst(ptr_type_node, 0xdeadc0c0); call = gimple_build_call(kaapi_pushtask_decl, 2, sp, thread); gsi_insert_before(&gsi, call, GSI_SAME_STMT); /* kaapi_barrier(); */ call = gimple_build_call(kaapi_barrier_decl, 0); gsi_replace(&gsi, call, true); }
static void adjust_simduid_builtins (hash_table<simduid_to_vf> *htab) { basic_block bb; FOR_EACH_BB_FN (bb, cfun) { gimple_stmt_iterator i; for (i = gsi_start_bb (bb); !gsi_end_p (i); ) { unsigned int vf = 1; enum internal_fn ifn; gimple *stmt = gsi_stmt (i); tree t; if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt)) { gsi_next (&i); continue; } ifn = gimple_call_internal_fn (stmt); switch (ifn) { case IFN_GOMP_SIMD_LANE: case IFN_GOMP_SIMD_VF: case IFN_GOMP_SIMD_LAST_LANE: break; case IFN_GOMP_SIMD_ORDERED_START: case IFN_GOMP_SIMD_ORDERED_END: if (integer_onep (gimple_call_arg (stmt, 0))) { enum built_in_function bcode = (ifn == IFN_GOMP_SIMD_ORDERED_START ? BUILT_IN_GOMP_ORDERED_START : BUILT_IN_GOMP_ORDERED_END); gimple *g = gimple_build_call (builtin_decl_explicit (bcode), 0); tree vdef = gimple_vdef (stmt); gimple_set_vdef (g, vdef); SSA_NAME_DEF_STMT (vdef) = g; gimple_set_vuse (g, gimple_vuse (stmt)); gsi_replace (&i, g, true); continue; } gsi_remove (&i, true); unlink_stmt_vdef (stmt); continue; default: gsi_next (&i); continue; } tree arg = gimple_call_arg (stmt, 0); gcc_assert (arg != NULL_TREE); gcc_assert (TREE_CODE (arg) == SSA_NAME); simduid_to_vf *p = NULL, data; data.simduid = DECL_UID (SSA_NAME_VAR (arg)); /* Need to nullify loop safelen field since it's value is not valid after transformation. */ if (bb->loop_father && bb->loop_father->safelen > 0) bb->loop_father->safelen = 0; if (htab) { p = htab->find (&data); if (p) vf = p->vf; } switch (ifn) { case IFN_GOMP_SIMD_VF: t = build_int_cst (unsigned_type_node, vf); break; case IFN_GOMP_SIMD_LANE: t = build_int_cst (unsigned_type_node, 0); break; case IFN_GOMP_SIMD_LAST_LANE: t = gimple_call_arg (stmt, 1); break; default: gcc_unreachable (); } update_call_from_tree (&i, t); gsi_next (&i); } }
void ubsan_expand_null_ifn (gimple_stmt_iterator gsi) { gimple stmt = gsi_stmt (gsi); location_t loc = gimple_location (stmt); gcc_assert (gimple_call_num_args (stmt) == 2); tree ptr = gimple_call_arg (stmt, 0); tree ckind = gimple_call_arg (stmt, 1); basic_block cur_bb = gsi_bb (gsi); /* Split the original block holding the pointer dereference. */ edge e = split_block (cur_bb, stmt); /* Get a hold on the 'condition block', the 'then block' and the 'else block'. */ basic_block cond_bb = e->src; basic_block fallthru_bb = e->dest; basic_block then_bb = create_empty_bb (cond_bb); add_bb_to_loop (then_bb, cond_bb->loop_father); loops_state_set (LOOPS_NEED_FIXUP); /* Make an edge coming from the 'cond block' into the 'then block'; this edge is unlikely taken, so set up the probability accordingly. */ e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE); e->probability = PROB_VERY_UNLIKELY; /* Connect 'then block' with the 'else block'. This is needed as the ubsan routines we call in the 'then block' are not noreturn. The 'then block' only has one outcoming edge. */ make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU); /* Set up the fallthrough basic block. */ e = find_edge (cond_bb, fallthru_bb); e->flags = EDGE_FALSE_VALUE; e->count = cond_bb->count; e->probability = REG_BR_PROB_BASE - PROB_VERY_UNLIKELY; /* Update dominance info for the newly created then_bb; note that fallthru_bb's dominance info has already been updated by split_bock. */ if (dom_info_available_p (CDI_DOMINATORS)) set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb); /* Put the ubsan builtin call into the newly created BB. */ gimple g; if (flag_sanitize_undefined_trap_on_error) g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0); else { enum built_in_function bcode = flag_sanitize_recover ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT; tree fn = builtin_decl_implicit (bcode); const struct ubsan_mismatch_data m = { build_zero_cst (pointer_sized_int_node), ckind }; tree data = ubsan_create_data ("__ubsan_null_data", &loc, &m, ubsan_type_descriptor (TREE_TYPE (ptr), UBSAN_PRINT_POINTER), NULL_TREE); data = build_fold_addr_expr_loc (loc, data); g = gimple_build_call (fn, 2, data, build_zero_cst (pointer_sized_int_node)); } gimple_set_location (g, loc); gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb); gsi_insert_after (&gsi2, g, GSI_NEW_STMT); /* Unlink the UBSAN_NULLs vops before replacing it. */ unlink_stmt_vdef (stmt); g = gimple_build_cond (EQ_EXPR, ptr, build_int_cst (TREE_TYPE (ptr), 0), NULL_TREE, NULL_TREE); gimple_set_location (g, loc); /* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */ gsi_replace (&gsi, g, false); }
static void use_internal_fn (gcall *call) { /* We'll be inserting another call with the same arguments after the lhs has been set, so prevent any possible coalescing failure from having both values live at once. See PR 71020. */ replace_abnormal_ssa_names (call); unsigned nconds = 0; auto_vec<gimple *, 12> conds; if (can_test_argument_range (call)) { gen_shrink_wrap_conditions (call, conds, &nconds); gcc_assert (nconds != 0); } else gcc_assert (edom_only_function (call)); internal_fn ifn = replacement_internal_fn (call); gcc_assert (ifn != IFN_LAST); /* Construct the new call, with the same arguments as the original one. */ auto_vec <tree, 16> args; unsigned int nargs = gimple_call_num_args (call); for (unsigned int i = 0; i < nargs; ++i) args.safe_push (gimple_call_arg (call, i)); gcall *new_call = gimple_build_call_internal_vec (ifn, args); gimple_set_location (new_call, gimple_location (call)); gimple_call_set_nothrow (new_call, gimple_call_nothrow_p (call)); /* Transfer the LHS to the new call. */ tree lhs = gimple_call_lhs (call); gimple_call_set_lhs (new_call, lhs); gimple_call_set_lhs (call, NULL_TREE); SSA_NAME_DEF_STMT (lhs) = new_call; /* Insert the new call. */ gimple_stmt_iterator gsi = gsi_for_stmt (call); gsi_insert_before (&gsi, new_call, GSI_SAME_STMT); if (nconds == 0) { /* Skip the call if LHS == LHS. If we reach here, EDOM is the only valid errno value and it is used iff the result is NaN. */ conds.quick_push (gimple_build_cond (EQ_EXPR, lhs, lhs, NULL_TREE, NULL_TREE)); nconds++; /* Try replacing the original call with a direct assignment to errno, via an internal function. */ if (set_edom_supported_p () && !stmt_ends_bb_p (call)) { gimple_stmt_iterator gsi = gsi_for_stmt (call); gcall *new_call = gimple_build_call_internal (IFN_SET_EDOM, 0); gimple_set_vuse (new_call, gimple_vuse (call)); gimple_set_vdef (new_call, gimple_vdef (call)); SSA_NAME_DEF_STMT (gimple_vdef (new_call)) = new_call; gimple_set_location (new_call, gimple_location (call)); gsi_replace (&gsi, new_call, false); call = new_call; } } shrink_wrap_one_built_in_call_with_conds (call, conds, nconds); }