static unsigned int instrument_assignments_plugin_exec(void) { #ifdef DEBUG fprintf(stderr, "* Inspecting function `%s'\n", FN_NAME); #endif basic_block bb; FOR_EACH_BB(bb) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb(bb) ; !gsi_end_p(gsi) ; gsi_next(&gsi)) { gimple curr_stmt = gsi_stmt(gsi); tree lhs = gimple_get_lhs(curr_stmt); // We only care about assignments to “real” variables – i.e. not // variable versions that were created as part of the transformation // to SSA form. if (gimple_code(curr_stmt) == GIMPLE_ASSIGN && lhs != NULL_TREE && TREE_CODE(lhs) != SSA_NAME && DECL_P(lhs)) { tree attrlist = DECL_ATTRIBUTES(lhs); tree attr = lookup_attribute("instrument", attrlist); // the princess is in another castle if (attr == NULL_TREE) continue; // read the variable id that was passed to the `instrument' // attribute const_tree arg = TREE_VALUE(TREE_VALUE(attr)); tree var_id = build_int_cst(NULL_TREE, tree_low_cst (arg, 1)); #ifdef DEBUG fprintf(stderr, " > found assignment to instrumented variable `%s': \n\t", get_name(lhs)); print_gimple_stmt(stderr, curr_stmt, 0, 0); fprintf(stderr, "\tbase address of `%s' is %p\n", get_name(lhs), get_base_address(lhs)); #endif // insert our instrumentation function before the current // statement and pass along the rhs (i.e. the new value) tree rhs = gimple_op(curr_stmt, 1); insert_instrumentation_fn(curr_stmt, var_id, rhs); } } } #ifdef DEBUG fprintf(stderr, "\n"); #endif return 0; }
static void check_call (funct_state local, gimple call, bool ipa) { int flags = gimple_call_flags (call); tree callee_t = gimple_call_fndecl (call); bool possibly_throws = stmt_could_throw_p (call); bool possibly_throws_externally = (possibly_throws && stmt_can_throw_external (call)); if (possibly_throws) { unsigned int i; for (i = 0; i < gimple_num_ops (call); i++) if (gimple_op (call, i) && tree_could_throw_p (gimple_op (call, i))) { if (possibly_throws && cfun->can_throw_non_call_exceptions) { if (dump_file) fprintf (dump_file, " operand can throw; looping\n"); local->looping = true; } if (possibly_throws_externally) { if (dump_file) fprintf (dump_file, " operand can throw externally\n"); local->can_throw = true; } } } /* The const and pure flags are set by a variety of places in the compiler (including here). If someone has already set the flags for the callee, (such as for some of the builtins) we will use them, otherwise we will compute our own information. Const and pure functions have less clobber effects than other functions so we process these first. Otherwise if it is a call outside the compilation unit or an indirect call we punt. This leaves local calls which will be processed by following the call graph. */ if (callee_t) { enum pure_const_state_e call_state; bool call_looping; if (special_builtin_state (&call_state, &call_looping, callee_t)) { worse_state (&local->pure_const_state, &local->looping, call_state, call_looping); return; } /* When bad things happen to bad functions, they cannot be const or pure. */ if (setjmp_call_p (callee_t)) { if (dump_file) fprintf (dump_file, " setjmp is not const/pure\n"); local->looping = true; local->pure_const_state = IPA_NEITHER; } if (DECL_BUILT_IN_CLASS (callee_t) == BUILT_IN_NORMAL) switch (DECL_FUNCTION_CODE (callee_t)) { case BUILT_IN_LONGJMP: case BUILT_IN_NONLOCAL_GOTO: if (dump_file) fprintf (dump_file, " longjmp and nonlocal goto is not const/pure\n"); local->pure_const_state = IPA_NEITHER; local->looping = true; break; default: break; } } /* When not in IPA mode, we can still handle self recursion. */ if (!ipa && callee_t == current_function_decl) { if (dump_file) fprintf (dump_file, " Recursive call can loop.\n"); local->looping = true; } /* Either callee is unknown or we are doing local analysis. Look to see if there are any bits available for the callee (such as by declaration or because it is builtin) and process solely on the basis of those bits. */ else if (!ipa) { enum pure_const_state_e call_state; bool call_looping; if (possibly_throws && cfun->can_throw_non_call_exceptions) { if (dump_file) fprintf (dump_file, " can throw; looping\n"); local->looping = true; } if (possibly_throws_externally) { if (dump_file) { fprintf (dump_file, " can throw externally to lp %i\n", lookup_stmt_eh_lp (call)); if (callee_t) fprintf (dump_file, " callee:%s\n", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (callee_t))); } local->can_throw = true; } if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " checking flags for call:"); state_from_flags (&call_state, &call_looping, flags, ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)) || (!flag_exceptions && (flags & ECF_NORETURN))); worse_state (&local->pure_const_state, &local->looping, call_state, call_looping); } /* Direct functions calls are handled by IPA propagation. */ }
static bool stmt_simple_for_scop_p (basic_block scop_entry, loop_p outermost_loop, gimple stmt, basic_block bb) { loop_p loop = bb->loop_father; gcc_assert (scop_entry); /* GIMPLE_ASM and GIMPLE_CALL may embed arbitrary side effects. Calls have side-effects, except those to const or pure functions. */ if (gimple_has_volatile_ops (stmt) || (gimple_code (stmt) == GIMPLE_CALL && !(gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))) || (gimple_code (stmt) == GIMPLE_ASM)) return false; if (is_gimple_debug (stmt)) return true; if (!stmt_has_simple_data_refs_p (outermost_loop, stmt)) return false; switch (gimple_code (stmt)) { case GIMPLE_RETURN: case GIMPLE_LABEL: return true; case GIMPLE_COND: { /* We can handle all binary comparisons. Inequalities are also supported as they can be represented with union of polyhedra. */ enum tree_code code = gimple_cond_code (stmt); if (!(code == LT_EXPR || code == GT_EXPR || code == LE_EXPR || code == GE_EXPR || code == EQ_EXPR || code == NE_EXPR)) return false; for (unsigned i = 0; i < 2; ++i) { tree op = gimple_op (stmt, i); if (!graphite_can_represent_expr (scop_entry, loop, op) /* We can not handle REAL_TYPE. Failed for pr39260. */ || TREE_CODE (TREE_TYPE (op)) == REAL_TYPE) return false; } return true; } case GIMPLE_ASSIGN: case GIMPLE_CALL: return true; default: /* These nodes cut a new scope. */ return false; } return false; }
static void output_gimple_stmt (struct output_block *ob, gimple stmt) { unsigned i; enum gimple_code code; enum LTO_tags tag; struct bitpack_d bp; histogram_value hist; /* Emit identifying tag. */ code = gimple_code (stmt); tag = lto_gimple_code_to_tag (code); streamer_write_record_start (ob, tag); /* Emit the tuple header. */ bp = bitpack_create (ob->main_stream); bp_pack_var_len_unsigned (&bp, gimple_num_ops (stmt)); bp_pack_value (&bp, gimple_no_warning_p (stmt), 1); if (is_gimple_assign (stmt)) bp_pack_value (&bp, gimple_assign_nontemporal_move_p (stmt), 1); bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1); hist = gimple_histogram_value (cfun, stmt); bp_pack_value (&bp, hist != NULL, 1); bp_pack_var_len_unsigned (&bp, stmt->gsbase.subcode); /* Emit location information for the statement. */ stream_output_location (ob, &bp, LOCATION_LOCUS (gimple_location (stmt))); streamer_write_bitpack (&bp); /* Emit the lexical block holding STMT. */ stream_write_tree (ob, gimple_block (stmt), true); /* Emit the operands. */ switch (gimple_code (stmt)) { case GIMPLE_RESX: streamer_write_hwi (ob, gimple_resx_region (stmt)); break; case GIMPLE_EH_MUST_NOT_THROW: stream_write_tree (ob, gimple_eh_must_not_throw_fndecl (stmt), true); break; case GIMPLE_EH_DISPATCH: streamer_write_hwi (ob, gimple_eh_dispatch_region (stmt)); break; case GIMPLE_ASM: streamer_write_uhwi (ob, gimple_asm_ninputs (stmt)); streamer_write_uhwi (ob, gimple_asm_noutputs (stmt)); streamer_write_uhwi (ob, gimple_asm_nclobbers (stmt)); streamer_write_uhwi (ob, gimple_asm_nlabels (stmt)); streamer_write_string (ob, ob->main_stream, gimple_asm_string (stmt), true); /* Fallthru */ case GIMPLE_ASSIGN: case GIMPLE_CALL: case GIMPLE_RETURN: case GIMPLE_SWITCH: case GIMPLE_LABEL: case GIMPLE_COND: case GIMPLE_GOTO: case GIMPLE_DEBUG: for (i = 0; i < gimple_num_ops (stmt); i++) { tree op = gimple_op (stmt, i); tree *basep = NULL; /* Wrap all uses of non-automatic variables inside MEM_REFs so that we do not have to deal with type mismatches on merged symbols during IL read in. The first operand of GIMPLE_DEBUG must be a decl, not MEM_REF, though. */ if (op && (i || !is_gimple_debug (stmt))) { basep = &op; while (handled_component_p (*basep)) basep = &TREE_OPERAND (*basep, 0); if (TREE_CODE (*basep) == VAR_DECL && !auto_var_in_fn_p (*basep, current_function_decl) && !DECL_REGISTER (*basep)) { bool volatilep = TREE_THIS_VOLATILE (*basep); *basep = build2 (MEM_REF, TREE_TYPE (*basep), build_fold_addr_expr (*basep), build_int_cst (build_pointer_type (TREE_TYPE (*basep)), 0)); TREE_THIS_VOLATILE (*basep) = volatilep; } else basep = NULL; } stream_write_tree (ob, op, true); /* Restore the original base if we wrapped it inside a MEM_REF. */ if (basep) *basep = TREE_OPERAND (TREE_OPERAND (*basep, 0), 0); } if (is_gimple_call (stmt)) { if (gimple_call_internal_p (stmt)) streamer_write_enum (ob->main_stream, internal_fn, IFN_LAST, gimple_call_internal_fn (stmt)); else stream_write_tree (ob, gimple_call_fntype (stmt), true); } break; case GIMPLE_NOP: case GIMPLE_PREDICT: break; case GIMPLE_TRANSACTION: gcc_assert (gimple_transaction_body (stmt) == NULL); stream_write_tree (ob, gimple_transaction_label (stmt), true); break; default: gcc_unreachable (); } if (hist) stream_out_histogram_value (ob, hist); }
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); }
static void read_stmt( gimple g, t_myproof_function *function ) { unsigned int i; enum gimple_code gc; gc = gimple_code( g ); switch ( gc ) { case GIMPLE_ASSIGN: { t_myproof_variable *op1 = read_operand( gimple_op(g,1), function ); /* op1 */ if ( op1 ) { op1->visited++; } if ( gimple_num_ops(g) > 2 ) /* op2 */ { t_myproof_variable *op2 = read_operand( gimple_op(g,2), function ); if ( op2 ) { op2->visited++; } } t_myproof_variable *opdef = read_operand( gimple_op(g,0), function ); /* op def */ if ( opdef ) { opdef->modified++; } } break; case GIMPLE_CALL: for ( i = 0; i < gimple_call_num_args(g); ++i ) { read_operand( gimple_call_arg(g,i), function ); } if ( gimple_call_lhs(g) != NULL_TREE ) { read_operand( gimple_call_lhs(g), function ); } break; case GIMPLE_COND: read_operand( gimple_cond_lhs(g), function ); /* op1 */ read_operand( gimple_cond_rhs(g), function ); /* op2 */ break; case GIMPLE_RETURN: if ( gimple_return_retval(g) != NULL_TREE ) { read_operand( gimple_return_retval(g), function ); } break; case GIMPLE_DEBUG: break; default: fprintf( stderr, "myproof: read_stmt(): unhandled \'%s\'\n", gimple_code_name[gc] ); gcc_unreachable ( ); } }
static void read_stmt( gimple g ) { unsigned int i; enum gimple_code gc; gc = gimple_code( g ); /* debug_tree(type1); */ //debug_tree(type1); /* switch ( gc ) */ /* { */ /* case GIMPLE_ASSIGN: */ /* case GIMPLE_CALL: */ /* case GIMPLE_COND: */ /* case GIMPLE_RETURN: */ /* num_all_ops += gimple_num_ops(g); */ /* } */ switch ( gc ) { case GIMPLE_ASSIGN: read_operand( gimple_op(g,1) ); /* op1 */ /* num_all_ops_write++; */ tree type1 = TREE_TYPE( gimple_op( g, 1 ) ); int tc = TREE_CODE( type1 ); if ( tc == REAL_TYPE ) { //debug_tree(type1); /* printf("this is a real variable\n"); */ } /* enum tree_code tr = gimple_assign_rhs_code(g); */ /* printf("Doing %s\n", tree_code_name[tr]); */ if ( gimple_num_ops(g) > 2 ) /* op2 */ { read_operand( gimple_op(g,2) ); } read_operand( gimple_op(g,0) ); /* op def */ break; case GIMPLE_CALL: for ( i = 0; i < gimple_call_num_args(g); ++i ) { read_operand( gimple_call_arg(g,i) ); } if ( gimple_call_lhs(g) != NULL_TREE ) { read_operand( gimple_call_lhs(g) ); } break; case GIMPLE_COND: read_operand( gimple_cond_lhs(g) ); /* op1 */ read_operand( gimple_cond_rhs(g) ); /* op2 */ break; case GIMPLE_RETURN: if ( gimple_return_retval(g) != NULL_TREE ) { read_operand( gimple_return_retval(g) ); } break; case GIMPLE_DEBUG: break; default: fprintf( stderr, "myproof: read_stmt(): unhandled \'%s\'\n", gimple_code_name[gc] ); gcc_unreachable ( ); } }
static void myprof_read_stmt ( gimple g, int *nbop) { unsigned int i; enum gimple_code gc; /* nbloads = 0;*/ /* nbstores = 0;*/ /* fprintf(stderr, "nbop dans mihp_read_stmt: %d\n", *nbop);*/ gc = gimple_code ( g ); switch ( gc ) { case GIMPLE_ASSIGN: (*nbop)++; //fprintf(stderr, "dans mihp_read_stmt, nombre d'operations: %d\n", *nbop); //Premier opérande à droite de l'égalité myprof_read_operand ( gimple_op(g,1), RIGHT ); /* op1 */ if ( gimple_num_ops(g) > 2 ) {/* op2 */ /* printf("Plus de 2 operandes\n");*/ /* printf("Type d'operation: %d\n", gimple_assign_rhs_code(g));*/ /* printf("Type d'operation: %s\n", tree_code_name[gimple_assign_rhs_code(g)]);*/ //nb2opSuperior++; myprof_read_operand ( gimple_op(g,2), RIGHT ); //debug_tree(gimple_op(gsi_stmt(gsi),1)); tree type1 = TREE_TYPE(gimple_op(g,1)); tree type2 = TREE_TYPE(gimple_op(g,2)); /* debug_tree(type1);*/ /* debug_tree(type2);*/ int tc = TREE_CODE(type1); int tc2 = TREE_CODE(type2); if((tc == REAL_TYPE) || (tc2 == REAL_TYPE)) { /* fprintf(stderr, "l'operation est de type reel\n");*/ } else { /* fprintf(stderr, "l'operation est de type entier\n");*/ } /* if(tc == REAL_TYPE) {*/ /* fprintf(stderr, "type Réel\n");*/ /* } */ /* else if(tc == INTEGER_TYPE) {*/ /* fprintf(stderr, "type Entier\n");*/ /* }*/ } myprof_read_operand ( gimple_op(g,0), LEFT ); /* op def */ break; case GIMPLE_CALL: for ( i=0; i<gimple_call_num_args(g); ++i ) myprof_read_operand ( gimple_call_arg(g,i), 2 ); if ( gimple_call_lhs(g) != NULL_TREE ) myprof_read_operand ( gimple_call_lhs(g), 2 ); break; case GIMPLE_COND: myprof_read_operand ( gimple_cond_lhs(g), 2 ); /* op1 */ myprof_read_operand ( gimple_cond_rhs(g), 2 ); /* op2 */ break; case GIMPLE_RETURN: if ( gimple_return_retval(g) != NULL_TREE ) myprof_read_operand ( gimple_return_retval(g), 2 ); break; default: fprintf ( stderr, "mihp: mihp_read_stmt(): unhandled \'%s\'\n", gimple_code_name[gc] ); gcc_unreachable ( ); } }