static void lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data) { gimple stmt = gsi_stmt (*gsi); gimple t; int i; return_statements_t tmp_rs; /* Match this up with an existing return statement that's been created. */ for (i = data->return_statements.length () - 1; i >= 0; i--) { tmp_rs = data->return_statements[i]; if (gimple_return_retval (stmt) == gimple_return_retval (tmp_rs.stmt)) { /* Remove the line number from the representative return statement. It now fills in for many such returns. Failure to remove this will result in incorrect results for coverage analysis. */ gimple_set_location (tmp_rs.stmt, UNKNOWN_LOCATION); goto found; } } /* Not found. Create a new label and record the return statement. */ tmp_rs.label = create_artificial_label (cfun->function_end_locus); tmp_rs.stmt = stmt; data->return_statements.safe_push (tmp_rs); /* Generate a goto statement and remove the return statement. */ found: /* When not optimizing, make sure user returns are preserved. */ if (!optimize && gimple_has_location (stmt)) DECL_ARTIFICIAL (tmp_rs.label) = 0; t = gimple_build_goto (tmp_rs.label); gimple_set_location (t, gimple_location (stmt)); gimple_set_block (t, gimple_block (stmt)); gsi_insert_before (gsi, t, GSI_SAME_STMT); gsi_remove (gsi, false); }
static void compare_and_warn (gimple stmt, tree lhs, tree rhs) { if (operand_equal_p (lhs, rhs, OEP_PURE_SAME)) { location_t location; location = (gimple_has_location (stmt) ? gimple_location (stmt) : (DECL_P (lhs) ? DECL_SOURCE_LOCATION (lhs) : input_location)); /* If LHS contains any tree node not currently supported by get_non_ssa_expr, simply emit a generic warning without specifying LHS in the message. */ lhs = get_non_ssa_expr (lhs); if (lhs) warning_at (location, 0, G_("%qE is assigned to itself"), lhs); else warning_at (location, 0, G_("self-assignment detected")); } }
static void set_location_for_edge (edge e) { if (e->goto_locus) { set_curr_insn_source_location (e->goto_locus); set_curr_insn_block (e->goto_block); } else { basic_block bb = e->src; gimple_stmt_iterator gsi; do { for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) { gimple stmt = gsi_stmt (gsi); if (is_gimple_debug (stmt)) continue; if (gimple_has_location (stmt) || gimple_block (stmt)) { set_curr_insn_source_location (gimple_location (stmt)); set_curr_insn_block (gimple_block (stmt)); return; } } /* Nothing found in this basic block. Make a half-assed attempt to continue with another block. */ if (single_pred_p (bb)) bb = single_pred (bb); else bb = e->src; } while (bb != e->src); } }
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; } }
tree walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, walk_tree_fn callback_op, struct walk_stmt_info *wi) { gimple *ret; tree tree_ret; gimple *stmt = gsi_stmt (*gsi); if (wi) { wi->gsi = *gsi; wi->removed_stmt = false; if (wi->want_locations && gimple_has_location (stmt)) input_location = gimple_location (stmt); } ret = NULL; /* Invoke the statement callback. Return if the callback handled all of STMT operands by itself. */ if (callback_stmt) { bool handled_ops = false; tree_ret = callback_stmt (gsi, &handled_ops, wi); if (handled_ops) return tree_ret; /* If CALLBACK_STMT did not handle operands, it should not have a value to return. */ gcc_assert (tree_ret == NULL); if (wi && wi->removed_stmt) return NULL; /* Re-read stmt in case the callback changed it. */ stmt = gsi_stmt (*gsi); } /* If CALLBACK_OP is defined, invoke it on every operand of STMT. */ if (callback_op) { tree_ret = walk_gimple_op (stmt, callback_op, wi); if (tree_ret) return tree_ret; } /* If STMT can have statements inside (e.g. GIMPLE_BIND), walk them. */ switch (gimple_code (stmt)) { case GIMPLE_BIND: ret = walk_gimple_seq_mod (gimple_bind_body_ptr (as_a <gbind *> (stmt)), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; break; case GIMPLE_CATCH: ret = walk_gimple_seq_mod (gimple_catch_handler_ptr ( as_a <gcatch *> (stmt)), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; break; case GIMPLE_EH_FILTER: ret = walk_gimple_seq_mod (gimple_eh_filter_failure_ptr (stmt), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; break; case GIMPLE_EH_ELSE: { geh_else *eh_else_stmt = as_a <geh_else *> (stmt); ret = walk_gimple_seq_mod (gimple_eh_else_n_body_ptr (eh_else_stmt), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; ret = walk_gimple_seq_mod (gimple_eh_else_e_body_ptr (eh_else_stmt), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; } break; case GIMPLE_TRY: ret = walk_gimple_seq_mod (gimple_try_eval_ptr (stmt), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; ret = walk_gimple_seq_mod (gimple_try_cleanup_ptr (stmt), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; break; case GIMPLE_OMP_FOR: ret = walk_gimple_seq_mod (gimple_omp_for_pre_body_ptr (stmt), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; /* FALL THROUGH. */ case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TARGET: case GIMPLE_OMP_TEAMS: ret = walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; break; case GIMPLE_WITH_CLEANUP_EXPR: ret = walk_gimple_seq_mod (gimple_wce_cleanup_ptr (stmt), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; break; case GIMPLE_TRANSACTION: ret = walk_gimple_seq_mod (gimple_transaction_body_ptr ( as_a <gtransaction *> (stmt)), callback_stmt, callback_op, wi); if (ret) return wi->callback_result; break; default: gcc_assert (!gimple_has_substatements (stmt)); break; } return NULL; }
static unsigned int on_execute_pass(void) { basic_block bb; gimple_stmt_iterator gsi; const char* name; const char* file = EXPR_FILENAME(cfun->decl); const unsigned int line = EXPR_LINENO(cfun->decl); TRACE(); if (DECL_ASSEMBLER_NAME(cfun->decl) == NULL) { printf("--- skipping anonymous function\n"); return 0; } name = IDENTIFIER_POINTER(DECL_ASSEMBLER_NAME(cfun->decl)); #if 0 /* debug */ printf("--- passing on function: %s\n", name); #endif track_pragmed_func(file, line, name); FOR_EACH_BB(bb) { for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { const_gimple stmt = gsi_stmt(gsi); const enum gimple_code code = gimple_code(stmt); if (code == GIMPLE_CALL) { const char* const name = get_called_name(stmt); const tracked_func_t* const tf = find_tracked_func(name); printf("CALL%s: %s()\n", tf ? "_TASK" : "", name); if (tf != NULL) handle_task_call(gsi, tf); } #if 0 /* debug */ if (gimple_has_location(stmt)) { const location_t loc = gimple_location(stmt); const char* type = "STMT"; if (code == GIMPLE_CALL) printf ( "%s locus: .%s/%u.\n", type, LOCATION_FILE(loc), LOCATION_LINE(loc) ); } #endif /* debug */ } } return 0; }