static void change_orig_node(struct visited *visited, gimple stmt, const_tree orig_node, tree new_node, unsigned int num) { tree cast_lhs = cast_to_orig_type(visited, stmt, orig_node, new_node); switch (gimple_code(stmt)) { case GIMPLE_RETURN: gimple_return_set_retval(as_a_greturn(stmt), cast_lhs); break; case GIMPLE_CALL: gimple_call_set_arg(stmt, num - 1, cast_lhs); break; case GIMPLE_ASM: change_size_overflow_asm_input(as_a_gasm(stmt), cast_lhs); break; default: debug_gimple_stmt(stmt); gcc_unreachable(); } update_stmt(stmt); }
/* Verify cgraph nodes of given cgraph node. */ void verify_cgraph_node (struct cgraph_node *node) { struct cgraph_edge *e; struct cgraph_node *main_clone; struct function *this_cfun = DECL_STRUCT_FUNCTION (node->decl); struct function *saved_cfun = cfun; basic_block this_block; gimple_stmt_iterator gsi; bool error_found = false; if (errorcount || sorrycount) return; timevar_push (TV_CGRAPH_VERIFY); /* debug_generic_stmt needs correct cfun */ set_cfun (this_cfun); for (e = node->callees; e; e = e->next_callee) if (e->aux) { error ("aux field set for edge %s->%s", cgraph_node_name (e->caller), cgraph_node_name (e->callee)); error_found = true; } if (node->count < 0) { error ("Execution count is negative"); error_found = true; } for (e = node->callers; e; e = e->next_caller) { if (e->count < 0) { error ("caller edge count is negative"); error_found = true; } if (e->frequency < 0) { error ("caller edge frequency is negative"); error_found = true; } if (e->frequency > CGRAPH_FREQ_MAX) { error ("caller edge frequency is too large"); error_found = true; } if (!e->inline_failed) { if (node->global.inlined_to != (e->caller->global.inlined_to ? e->caller->global.inlined_to : e->caller)) { error ("inlined_to pointer is wrong"); error_found = true; } if (node->callers->next_caller) { error ("multiple inline callers"); error_found = true; } } else if (node->global.inlined_to) { error ("inlined_to pointer set for noninline callers"); error_found = true; } } if (!node->callers && node->global.inlined_to) { error ("inlined_to pointer is set but no predecessors found"); error_found = true; } if (node->global.inlined_to == node) { error ("inlined_to pointer refers to itself"); error_found = true; } for (main_clone = cgraph_node (node->decl); main_clone; main_clone = main_clone->next_clone) if (main_clone == node) break; if (!cgraph_node (node->decl)) { error ("node not found in cgraph_hash"); error_found = true; } if (node->analyzed && !TREE_ASM_WRITTEN (node->decl) && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to)) { if (this_cfun->cfg) { /* The nodes we're interested in are never shared, so walk the tree ignoring duplicates. */ struct pointer_set_t *visited_nodes = pointer_set_create (); /* Reach the trees by walking over the CFG, and note the enclosing basic-blocks in the call edges. */ FOR_EACH_BB_FN (this_block, this_cfun) for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); tree decl; if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) { struct cgraph_edge *e = cgraph_edge (node, stmt); if (e) { if (e->aux) { error ("shared call_stmt:"); debug_gimple_stmt (stmt); error_found = true; } if (e->callee->decl != cgraph_node (decl)->decl && e->inline_failed) { error ("edge points to wrong declaration:"); debug_tree (e->callee->decl); fprintf (stderr," Instead of:"); debug_tree (decl); } e->aux = (void *)1; } else { error ("missing callgraph edge for call stmt:"); debug_gimple_stmt (stmt); error_found = true; } } } pointer_set_destroy (visited_nodes); } else /* No CFG available?! */ gcc_unreachable (); for (e = node->callees; e; e = e->next_callee) { if (!e->aux && !e->indirect_call) { error ("edge %s->%s has no corresponding call_stmt", cgraph_node_name (e->caller), cgraph_node_name (e->callee)); debug_gimple_stmt (e->call_stmt); error_found = true; } e->aux = 0; } }
tree handle_fnptr_assign(const_gimple stmt) { tree field, rhs, op0; const_tree op0_type; enum tree_code rhs_code; // TODO skip binary assignments for now (fs/sync.c _591 = __bpf_call_base + _590;) if (gimple_num_ops(stmt) != 2) return NULL_TREE; gcc_assert(gimple_num_ops(stmt) == 2); // TODO skip asm_stmt for now if (gimple_code(stmt) == GIMPLE_ASM) return NULL_TREE; rhs = gimple_assign_rhs1(stmt); if (is_gimple_constant(rhs)) return NULL_TREE; rhs_code = TREE_CODE(rhs); if (rhs_code == VAR_DECL) return rhs; switch (rhs_code) { case ADDR_EXPR: op0 = TREE_OPERAND(rhs, 0); gcc_assert(TREE_CODE(op0) == FUNCTION_DECL); return op0; case COMPONENT_REF: break; // TODO skip array_ref for now case ARRAY_REF: return NULL_TREE; // TODO skip ssa_name because it can lead to parm_decl case SSA_NAME: return NULL_TREE; // TODO skip mem_ref and indirect_ref for now #if BUILDING_GCC_VERSION >= 4006 case MEM_REF: #endif case INDIRECT_REF: return NULL_TREE; default: debug_tree(rhs); debug_gimple_stmt((gimple)stmt); gcc_unreachable(); } op0 = TREE_OPERAND(rhs, 0); switch (TREE_CODE(op0)) { // TODO skip array_ref and parm_decl for now case ARRAY_REF: case PARM_DECL: return NULL_TREE; case COMPONENT_REF: #if BUILDING_GCC_VERSION >= 4006 case MEM_REF: #endif case INDIRECT_REF: case VAR_DECL: break; default: debug_tree(op0); gcc_unreachable(); } op0_type = TREE_TYPE(op0); // TODO skip unions for now if (TREE_CODE(op0_type) == UNION_TYPE) return NULL_TREE; gcc_assert(TREE_CODE(op0_type) == RECORD_TYPE); field = TREE_OPERAND(rhs, 1); gcc_assert(TREE_CODE(field) == FIELD_DECL); return field; }