void debug_tree(b_tree_t* head, int depth) { if (!head) { printf("%*c<nil>\n", depth * INDENT_GAP, ' '); return; } printf("%*c%c\n", depth * INDENT_GAP, ' ', head->value); debug_tree(head->left, depth + 1); debug_tree(head->right, depth + 1); }
/** Usage: ./reconstruct <preorder> <order> */ int main(int argc, char** argv) { b_tree_t* tree; size_t length; if (argc != 3) print_usage(argc, argv); length = strlen(argv[1]); if (strlen(argv[2]) != length) FATAL_ERROR("Input with different lengths (%zu, %zu)\n", length, strlen(argv[2])); tree = b_tree_reconstruct_bulletproof(argv[1], argv[2], length); if (tree == NULL) FATAL_ERROR("Input is not convertible to tree\n"); printf("Conversion succeeded! you should see here your input:\n"); b_tree_preorder(tree, print_element, NULL); printf("\n"); b_tree_order(tree, print_element, NULL); printf("\n"); printf("Tree debugging:\n"); debug_tree(tree, 0); printf("\n"); b_tree_destroy(tree); return 0; }
static tree handle_nocapture_attribute(tree *node, tree __unused name, tree args, int __unused flags, bool *no_add_attrs) { tree orig_attr, arg; *no_add_attrs = true; switch (TREE_CODE(*node)) { case FUNCTION_DECL: case FUNCTION_TYPE: case METHOD_TYPE: break; case TYPE_DECL: { const_tree fntype = TREE_TYPE(*node); if (TREE_CODE(fntype) == POINTER_TYPE) fntype = TREE_TYPE(fntype); if (TREE_CODE(fntype) == FUNCTION_TYPE || TREE_CODE(fntype) == METHOD_TYPE) break; // FALLTHROUGH } default: error("%s: %qE attribute only applies to functions", __func__, name); debug_tree(*node); return NULL_TREE; } for (arg = args; arg; arg = TREE_CHAIN(arg)) { tree position = TREE_VALUE(arg); if (TREE_CODE(position) != INTEGER_CST) { error("%s: parameter isn't an integer", __func__); debug_tree(arg); return NULL_TREE; } } orig_attr = lookup_attribute("nocapture", DECL_ATTRIBUTES(*node)); if (orig_attr) chainon(TREE_VALUE(orig_attr), args); else *no_add_attrs = false; return NULL_TREE; }
void debug_tree(struct node *root, unsigned char *edge, int level) { for (int i = 0; i < level; ++i) printf(" "); printf("="); for (char *foo = edge; *foo; ++foo) printf("%c", *foo+'a'-1); printf("= %d\n", root->cnt); /*printf("=%s=\n", edge);*/ for (int i = 0; i < 27; ++i) { if (!root->go[i]) continue; debug_tree(root->go[i], root->edge[i], level+1); } }
/* * find all C level function pointer dereferences and forcibly set the highest bit of the pointer */ static unsigned int execute_kernexec_fptr(void) { basic_block bb; // 1. loop through BBs and GIMPLE statements FOR_EACH_BB(bb) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { // gimple match: h_1 = get_fptr (); D.2709_3 = h_1 (x_2(D)); tree fn; gimple call_stmt; // is it a call ... call_stmt = gsi_stmt(gsi); if (!is_gimple_call(call_stmt)) continue; fn = gimple_call_fn(call_stmt); if (TREE_CODE(fn) == ADDR_EXPR) continue; if (TREE_CODE(fn) != SSA_NAME) gcc_unreachable(); // ... through a function pointer if (SSA_NAME_VAR(fn) != NULL_TREE) { fn = SSA_NAME_VAR(fn); if (TREE_CODE(fn) != VAR_DECL && TREE_CODE(fn) != PARM_DECL) { debug_tree(fn); gcc_unreachable(); } } fn = TREE_TYPE(fn); if (TREE_CODE(fn) != POINTER_TYPE) continue; fn = TREE_TYPE(fn); if (TREE_CODE(fn) != FUNCTION_TYPE) continue; kernexec_instrument_fptr(&gsi); //debug_tree(gimple_call_fn(call_stmt)); //print_gimple_stmt(stderr, call_stmt, 0, TDF_LINENO); } } return 0; }
static unsigned char get_tree_code(const_tree type) { switch (TREE_CODE(type)) { case ARRAY_TYPE: return 0; case BOOLEAN_TYPE: return 1; case ENUMERAL_TYPE: return 2; case FUNCTION_TYPE: return 3; case INTEGER_TYPE: return 4; case POINTER_TYPE: return 5; case RECORD_TYPE: return 6; case UNION_TYPE: return 7; case VOID_TYPE: return 8; case REAL_TYPE: return 9; case VECTOR_TYPE: return 10; case REFERENCE_TYPE: return 11; case OFFSET_TYPE: return 12; case COMPLEX_TYPE: return 13; default: debug_tree(type); gcc_unreachable(); } }
/* 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; } }
void browse_tree (tree begin) { tree head; TB_CODE tbc = TB_UNUSED_COMMAND; ssize_t rd; char *input = NULL; long input_size = 0; fprintf (TB_OUT_FILE, "\nTree Browser\n"); #define TB_SET_HEAD(N) do { \ vec_safe_push (TB_history_stack, N); \ head = N; \ if (TB_verbose) \ if (head) \ { \ print_generic_expr (TB_OUT_FILE, head, 0); \ fprintf (TB_OUT_FILE, "\n"); \ } \ } while (0) TB_SET_HEAD (begin); /* Store in a hashtable information about previous and upper statements. */ { TB_up_ht = new hash_table<tree_upper_hasher> (1023); TB_update_up (head); } while (24) { fprintf (TB_OUT_FILE, "TB> "); rd = TB_getline (&input, &input_size, TB_IN_FILE); if (rd == -1) /* EOF. */ goto ret; if (rd != 1) /* Get a new command. Otherwise the user just pressed enter, and thus she expects the last command to be reexecuted. */ tbc = TB_get_command (input); switch (tbc) { case TB_UPDATE_UP: TB_update_up (head); break; case TB_MAX: if (head && (INTEGRAL_TYPE_P (head) || TREE_CODE (head) == REAL_TYPE || TREE_CODE (head) == FIXED_POINT_TYPE)) TB_SET_HEAD (TYPE_MAX_VALUE (head)); else TB_WF; break; case TB_MIN: if (head && (INTEGRAL_TYPE_P (head) || TREE_CODE (head) == REAL_TYPE || TREE_CODE (head) == FIXED_POINT_TYPE)) TB_SET_HEAD (TYPE_MIN_VALUE (head)); else TB_WF; break; case TB_ELT: if (head && TREE_CODE (head) == TREE_VEC) { /* This command takes another argument: the element number: for example "elt 1". */ TB_NIY; } else if (head && TREE_CODE (head) == VECTOR_CST) { /* This command takes another argument: the element number: for example "elt 1". */ TB_NIY; } else TB_WF; break; case TB_VALUE: if (head && TREE_CODE (head) == TREE_LIST) TB_SET_HEAD (TREE_VALUE (head)); else TB_WF; break; case TB_PURPOSE: if (head && TREE_CODE (head) == TREE_LIST) TB_SET_HEAD (TREE_PURPOSE (head)); else TB_WF; break; case TB_IMAG: if (head && TREE_CODE (head) == COMPLEX_CST) TB_SET_HEAD (TREE_IMAGPART (head)); else TB_WF; break; case TB_REAL: if (head && TREE_CODE (head) == COMPLEX_CST) TB_SET_HEAD (TREE_REALPART (head)); else TB_WF; break; case TB_BLOCK: if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 2)); else TB_WF; break; case TB_SUBBLOCKS: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_SUBBLOCKS (head)); else TB_WF; break; case TB_SUPERCONTEXT: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_SUPERCONTEXT (head)); else TB_WF; break; case TB_VARS: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_VARS (head)); else if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 0)); else TB_WF; break; case TB_REFERENCE_TO_THIS: if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_REFERENCE_TO (head)); else TB_WF; break; case TB_POINTER_TO_THIS: if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_POINTER_TO (head)); else TB_WF; break; case TB_BASETYPE: if (head && TREE_CODE (head) == OFFSET_TYPE) TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head)); else TB_WF; break; case TB_ARG_TYPES: if (head && (TREE_CODE (head) == FUNCTION_TYPE || TREE_CODE (head) == METHOD_TYPE)) TB_SET_HEAD (TYPE_ARG_TYPES (head)); else TB_WF; break; case TB_METHOD_BASE_TYPE: if (head && (TREE_CODE (head) == FUNCTION_TYPE || TREE_CODE (head) == METHOD_TYPE) && TYPE_METHOD_BASETYPE (head)) TB_SET_HEAD (TYPE_METHOD_BASETYPE (head)); else TB_WF; break; case TB_FIELDS: if (head && (TREE_CODE (head) == RECORD_TYPE || TREE_CODE (head) == UNION_TYPE || TREE_CODE (head) == QUAL_UNION_TYPE)) TB_SET_HEAD (TYPE_FIELDS (head)); else TB_WF; break; case TB_DOMAIN: if (head && TREE_CODE (head) == ARRAY_TYPE) TB_SET_HEAD (TYPE_DOMAIN (head)); else TB_WF; break; case TB_VALUES: if (head && TREE_CODE (head) == ENUMERAL_TYPE) TB_SET_HEAD (TYPE_VALUES (head)); else TB_WF; break; case TB_ARG_TYPE: if (head && TREE_CODE (head) == PARM_DECL) TB_SET_HEAD (DECL_ARG_TYPE (head)); else TB_WF; break; case TB_INITIAL: if (head && DECL_P (head)) TB_SET_HEAD (DECL_INITIAL (head)); else TB_WF; break; case TB_RESULT: if (head && DECL_P (head)) TB_SET_HEAD (DECL_RESULT_FLD (head)); else TB_WF; break; case TB_ARGUMENTS: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ARGUMENTS (head)); else TB_WF; break; case TB_ABSTRACT_ORIGIN: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head)); else if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head)); else TB_WF; break; case TB_ATTRIBUTES: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ATTRIBUTES (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_ATTRIBUTES (head)); else TB_WF; break; case TB_CONTEXT: if (head && DECL_P (head)) TB_SET_HEAD (DECL_CONTEXT (head)); else if (head && TYPE_P (head) && TYPE_CONTEXT (head)) TB_SET_HEAD (TYPE_CONTEXT (head)); else TB_WF; break; case TB_OFFSET: if (head && TREE_CODE (head) == FIELD_DECL) TB_SET_HEAD (DECL_FIELD_OFFSET (head)); else TB_WF; break; case TB_BIT_OFFSET: if (head && TREE_CODE (head) == FIELD_DECL) TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head)); else TB_WF; break; case TB_UNIT_SIZE: if (head && DECL_P (head)) TB_SET_HEAD (DECL_SIZE_UNIT (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_SIZE_UNIT (head)); else TB_WF; break; case TB_SIZE: if (head && DECL_P (head)) TB_SET_HEAD (DECL_SIZE (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_SIZE (head)); else TB_WF; break; case TB_TYPE: if (head && TREE_TYPE (head)) TB_SET_HEAD (TREE_TYPE (head)); else TB_WF; break; case TB_DECL_SAVED_TREE: if (head && TREE_CODE (head) == FUNCTION_DECL && DECL_SAVED_TREE (head)) TB_SET_HEAD (DECL_SAVED_TREE (head)); else TB_WF; break; case TB_BODY: if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 1)); else TB_WF; break; case TB_CHILD_0: if (head && EXPR_P (head) && TREE_OPERAND (head, 0)) TB_SET_HEAD (TREE_OPERAND (head, 0)); else TB_WF; break; case TB_CHILD_1: if (head && EXPR_P (head) && TREE_OPERAND (head, 1)) TB_SET_HEAD (TREE_OPERAND (head, 1)); else TB_WF; break; case TB_CHILD_2: if (head && EXPR_P (head) && TREE_OPERAND (head, 2)) TB_SET_HEAD (TREE_OPERAND (head, 2)); else TB_WF; break; case TB_CHILD_3: if (head && EXPR_P (head) && TREE_OPERAND (head, 3)) TB_SET_HEAD (TREE_OPERAND (head, 3)); else TB_WF; break; case TB_PRINT: if (head) debug_tree (head); else TB_WF; break; case TB_PRETTY_PRINT: if (head) { print_generic_stmt (TB_OUT_FILE, head, 0); fprintf (TB_OUT_FILE, "\n"); } else TB_WF; break; case TB_SEARCH_NAME: break; case TB_SEARCH_CODE: { enum tree_code code; char *arg_text; arg_text = strchr (input, ' '); if (arg_text == NULL) { fprintf (TB_OUT_FILE, "First argument is missing. This isn't a valid search command. \n"); break; } code = TB_get_tree_code (arg_text + 1); /* Search in the subtree a node with the given code. */ { tree res; res = walk_tree (&head, find_node_with_code, &code, NULL); if (res == NULL_TREE) { fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n"); } else { fprintf (TB_OUT_FILE, "Achoo! I got this node in the tree.\n"); TB_SET_HEAD (res); } } break; } #define TB_MOVE_HEAD(FCT) do { \ if (head) \ { \ tree t; \ t = FCT (head); \ if (t) \ TB_SET_HEAD (t); \ else \ TB_WF; \ } \ else \ TB_WF; \ } while (0) case TB_FIRST: TB_MOVE_HEAD (TB_first_in_bind); break; case TB_LAST: TB_MOVE_HEAD (TB_last_in_bind); break; case TB_UP: TB_MOVE_HEAD (TB_up_expr); break; case TB_PREV: TB_MOVE_HEAD (TB_prev_expr); break; case TB_NEXT: TB_MOVE_HEAD (TB_next_expr); break; case TB_HPREV: /* This command is a little bit special, since it deals with history stack. For this reason it should keep the "head = ..." statement and not use TB_MOVE_HEAD. */ if (head) { tree t; t = TB_history_prev (); if (t) { head = t; if (TB_verbose) { print_generic_expr (TB_OUT_FILE, head, 0); fprintf (TB_OUT_FILE, "\n"); } } else TB_WF; } else TB_WF; break; case TB_CHAIN: /* Don't go further if it's the last node in this chain. */ if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_CHAIN (head)); else if (head && TREE_CHAIN (head)) TB_SET_HEAD (TREE_CHAIN (head)); else TB_WF; break; case TB_FUN: /* Go up to the current function declaration. */ TB_SET_HEAD (current_function_decl); fprintf (TB_OUT_FILE, "Current function declaration.\n"); break; case TB_HELP: /* Display a help message. */ { int i; fprintf (TB_OUT_FILE, "Possible commands are:\n\n"); for (i = 0; i < TB_UNUSED_COMMAND; i++) { fprintf (TB_OUT_FILE, "%20s - %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i)); } } break; case TB_VERBOSE: if (TB_verbose == 0) { TB_verbose = 1; fprintf (TB_OUT_FILE, "Verbose on.\n"); } else { TB_verbose = 0; fprintf (TB_OUT_FILE, "Verbose off.\n"); } break; case TB_EXIT: case TB_QUIT: /* Just exit from this function. */ goto ret; default: TB_NIY; } } ret:; delete TB_up_ht; TB_up_ht = NULL; return; }
static tree handle_python_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) { PyObject *callable; /* Debug code: */ if (0) { printf("handle_python_attribute called\n"); fprintf(stderr, "node: "); debug_tree(*node); /* the site of the attribute e.g. a var_decl */ fprintf(stderr, "name: "); debug_tree(name); /* an identifier_node e.g. "custom_attribute_without_args" */ fprintf(stderr, "args: "); debug_tree(args); /* if present, a tree_list, e.g. of constants */ fprintf(stderr, "flags: %i\n", flags); fprintf(stderr, "and here!\n"); } /* How do we get to the attribute? This code: const struct attribute_spec *spec = lookup_attribute_spec (name); suggests that attributes must have unique names, so keep a dict mapping strings to callables */ assert(IDENTIFIER_NODE == TREE_CODE(name)); callable = PyDict_GetItemString(attribute_dict, IDENTIFIER_POINTER(name)); assert(callable); { PyGILState_STATE gstate; PyObject *py_args = NULL; PyObject *result = NULL; gstate = PyGILState_Ensure(); /* The args to the function call will be the node, plus the args of the attribute: */ py_args = make_args_for_attribute_callback(*node, args); if (!py_args) { goto cleanup; } result = PyObject_Call(callable, py_args, NULL); if (!result) { /* Treat an unhandled Python error as a compilation error: */ error("Unhandled Python exception raised within %s attribute handler", IDENTIFIER_POINTER(name)); PyErr_PrintEx(1); } /* (the result is ignored) */ cleanup: Py_XDECREF(py_args); Py_XDECREF(result); PyGILState_Release(gstate); } return NULL; // FIXME }
static void get_expr_operands (gimple stmt, tree *expr_p, int flags) { enum tree_code code; enum tree_code_class codeclass; tree expr = *expr_p; int uflags = opf_use; if (expr == NULL) return; if (is_gimple_debug (stmt)) uflags |= (flags & opf_no_vops); code = TREE_CODE (expr); codeclass = TREE_CODE_CLASS (code); switch (code) { case ADDR_EXPR: /* Taking the address of a variable does not represent a reference to it, but the fact that the statement takes its address will be of interest to some passes (e.g. alias resolution). */ if ((!(flags & opf_non_addressable) || (flags & opf_not_non_addressable)) && !is_gimple_debug (stmt)) mark_address_taken (TREE_OPERAND (expr, 0)); /* If the address is invariant, there may be no interesting variable references inside. */ if (is_gimple_min_invariant (expr)) return; /* Otherwise, there may be variables referenced inside but there should be no VUSEs created, since the referenced objects are not really accessed. The only operands that we should find here are ARRAY_REF indices which will always be real operands (GIMPLE does not allow non-registers as array indices). */ flags |= opf_no_vops; get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags | opf_not_non_addressable); return; case SSA_NAME: add_stmt_operand (expr_p, stmt, flags); return; case VAR_DECL: case PARM_DECL: case RESULT_DECL: add_stmt_operand (expr_p, stmt, flags); return; case DEBUG_EXPR_DECL: gcc_assert (gimple_debug_bind_p (stmt)); return; case MEM_REF: get_indirect_ref_operands (stmt, expr, flags, true); return; case TARGET_MEM_REF: get_tmr_operands (stmt, expr, flags); return; case ARRAY_REF: case ARRAY_RANGE_REF: case COMPONENT_REF: case REALPART_EXPR: case IMAGPART_EXPR: { if (TREE_THIS_VOLATILE (expr)) gimple_set_has_volatile_ops (stmt, true); get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags); if (code == COMPONENT_REF) { if (TREE_THIS_VOLATILE (TREE_OPERAND (expr, 1))) gimple_set_has_volatile_ops (stmt, true); get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags); } else if (code == ARRAY_REF || code == ARRAY_RANGE_REF) { get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags); get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags); get_expr_operands (stmt, &TREE_OPERAND (expr, 3), uflags); } return; } case WITH_SIZE_EXPR: /* WITH_SIZE_EXPR is a pass-through reference to its first argument, and an rvalue reference to its second argument. */ get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags); get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags); return; case COND_EXPR: case VEC_COND_EXPR: get_expr_operands (stmt, &TREE_OPERAND (expr, 0), uflags); get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags); get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags); return; case CONSTRUCTOR: { /* General aggregate CONSTRUCTORs have been decomposed, but they are still in use as the COMPLEX_EXPR equivalent for vectors. */ constructor_elt *ce; unsigned HOST_WIDE_INT idx; for (idx = 0; VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (expr), idx, ce); idx++) get_expr_operands (stmt, &ce->value, uflags); return; } case BIT_FIELD_REF: if (TREE_THIS_VOLATILE (expr)) gimple_set_has_volatile_ops (stmt, true); /* FALLTHRU */ case VIEW_CONVERT_EXPR: do_unary: get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags); return; case COMPOUND_EXPR: case OBJ_TYPE_REF: case ASSERT_EXPR: do_binary: { get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags); get_expr_operands (stmt, &TREE_OPERAND (expr, 1), flags); return; } case DOT_PROD_EXPR: case REALIGN_LOAD_EXPR: case WIDEN_MULT_PLUS_EXPR: case WIDEN_MULT_MINUS_EXPR: case FMA_EXPR: { get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags); get_expr_operands (stmt, &TREE_OPERAND (expr, 1), flags); get_expr_operands (stmt, &TREE_OPERAND (expr, 2), flags); return; } case FUNCTION_DECL: case LABEL_DECL: case CONST_DECL: case CASE_LABEL_EXPR: /* Expressions that make no memory references. */ return; default: if (codeclass == tcc_unary) goto do_unary; if (codeclass == tcc_binary || codeclass == tcc_comparison) goto do_binary; if (codeclass == tcc_constant || codeclass == tcc_type) return; } /* If we get here, something has gone wrong. */ #ifdef ENABLE_CHECKING fprintf (stderr, "unhandled expression in get_expr_operands():\n"); debug_tree (expr); fputs ("\n", stderr); #endif gcc_unreachable (); }
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; }
static void add_type_duplicate (odr_type val, tree type) { if (!val->types_set) val->types_set = pointer_set_create (); /* See if this duplicate is new. */ if (!pointer_set_insert (val->types_set, type)) { bool merge = true; bool base_mismatch = false; gcc_assert (in_lto_p); vec_safe_push (val->types, type); unsigned int i,j; /* First we compare memory layout. */ if (!types_compatible_p (val->type, type)) { merge = false; if (BINFO_VTABLE (TYPE_BINFO (val->type)) && warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0, "type %qD violates one definition rule ", type)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)), "a type with the same name but different layout is " "defined in another translation unit"); debug_tree (BINFO_VTABLE (TYPE_BINFO (type))); debug_tree (BINFO_VTABLE (TYPE_BINFO (val->type))); if (cgraph_dump_file) { fprintf (cgraph_dump_file, "ODR violation or merging or ODR type bug?\n"); print_node (cgraph_dump_file, "", val->type, 0); putc ('\n',cgraph_dump_file); print_node (cgraph_dump_file, "", type, 0); putc ('\n',cgraph_dump_file); } } /* Next sanity check that bases are the same. If not, we will end up producing wrong answers. */ for (j = 0, i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++) if (polymorphic_type_binfo_p (BINFO_BASE_BINFO (TYPE_BINFO (type), i))) { odr_type base = get_odr_type (BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type), i)), true); if (val->bases.length () <= j || val->bases[j] != base) base_mismatch = true; j++; } if (base_mismatch) { merge = false; if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0, "type %qD violates one definition rule ", type)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)), "a type with the same name but different bases is " "defined in another translation unit"); if (cgraph_dump_file) { fprintf (cgraph_dump_file, "ODR bse violation or merging bug?\n"); print_node (cgraph_dump_file, "", val->type, 0); putc ('\n',cgraph_dump_file); print_node (cgraph_dump_file, "", type, 0); putc ('\n',cgraph_dump_file); } } /* Regularize things a little. During LTO same types may come with different BINFOs. Either because their virtual table was not merged by tree merging and only later at decl merging or because one type comes with external vtable, while other with internal. We want to merge equivalent binfos to conserve memory and streaming overhead. The external vtables are more harmful: they contain references to external declarations of methods that may be defined in the merged LTO unit. For this reason we absolutely need to remove them and replace by internal variants. Not doing so will lead to incomplete answers from possible_polymorphic_call_targets. */ if (!flag_ltrans && merge) { tree master_binfo = TYPE_BINFO (val->type); tree v1 = BINFO_VTABLE (master_binfo); tree v2 = BINFO_VTABLE (TYPE_BINFO (type)); if (TREE_CODE (v1) == POINTER_PLUS_EXPR) { gcc_assert (TREE_CODE (v2) == POINTER_PLUS_EXPR && operand_equal_p (TREE_OPERAND (v1, 1), TREE_OPERAND (v2, 1), 0)); v1 = TREE_OPERAND (TREE_OPERAND (v1, 0), 0); v2 = TREE_OPERAND (TREE_OPERAND (v2, 0), 0); } gcc_assert (DECL_ASSEMBLER_NAME (v1) == DECL_ASSEMBLER_NAME (v2)); if (DECL_EXTERNAL (v1) && !DECL_EXTERNAL (v2)) { unsigned int i; TYPE_BINFO (val->type) = TYPE_BINFO (type); for (i = 0; i < val->types->length(); i++) { if (TYPE_BINFO ((*val->types)[i]) == master_binfo) TYPE_BINFO ((*val->types)[i]) = TYPE_BINFO (type); } } else TYPE_BINFO (type) = master_binfo; } } }