static void get_asm_expr_operands (funct_state local, tree stmt) { int noutputs = list_length (ASM_OUTPUTS (stmt)); const char **oconstraints = (const char **) alloca ((noutputs) * sizeof (const char *)); int i; tree link; const char *constraint; bool allows_mem, allows_reg, is_inout; for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link)) { oconstraints[i] = constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); parse_output_constraint (&constraint, i, 0, 0, &allows_mem, &allows_reg, &is_inout); check_lhs_var (local, TREE_VALUE (link)); } for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link)) { constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints, &allows_mem, &allows_reg); check_rhs_var (local, TREE_VALUE (link)); } for (link = ASM_CLOBBERS (stmt); link; link = TREE_CHAIN (link)) if (simple_cst_equal(TREE_VALUE (link), memory_identifier_string) == 1) /* Abandon all hope, ye who enter here. */ local->pure_const_state = IPA_NEITHER; if (ASM_VOLATILE_P (stmt)) local->pure_const_state = IPA_NEITHER; }
static tree scan_function (tree *tp, int *walk_subtrees, void *data) { struct cgraph_node *fn = data; tree t = *tp; funct_state local = get_function_state (fn); switch (TREE_CODE (t)) { case VAR_DECL: if (DECL_INITIAL (t)) walk_tree (&DECL_INITIAL (t), scan_function, fn, visited_nodes); *walk_subtrees = 0; break; case MODIFY_EXPR: { /* First look on the lhs and see what variable is stored to */ tree lhs = TREE_OPERAND (t, 0); tree rhs = TREE_OPERAND (t, 1); check_lhs_var (local, lhs); /* For the purposes of figuring out what the cast affects */ /* Next check the operands on the rhs to see if they are ok. */ switch (TREE_CODE_CLASS (TREE_CODE (rhs))) { case tcc_binary: { tree op0 = TREE_OPERAND (rhs, 0); tree op1 = TREE_OPERAND (rhs, 1); check_rhs_var (local, op0); check_rhs_var (local, op1); } break; case tcc_unary: { tree op0 = TREE_OPERAND (rhs, 0); check_rhs_var (local, op0); } break; case tcc_reference: check_rhs_var (local, rhs); break; case tcc_declaration: check_rhs_var (local, rhs); break; case tcc_expression: switch (TREE_CODE (rhs)) { case ADDR_EXPR: check_rhs_var (local, rhs); break; case CALL_EXPR: check_call (local, rhs); break; default: break; } break; default: break; } *walk_subtrees = 0; } break; case ADDR_EXPR: /* This case is here to find addresses on rhs of constructors in decl_initial of static variables. */ check_rhs_var (local, t); *walk_subtrees = 0; break; case LABEL_EXPR: if (DECL_NONLOCAL (TREE_OPERAND (t, 0))) /* Target of long jump. */ local->pure_const_state = IPA_NEITHER; break; case CALL_EXPR: check_call (local, t); *walk_subtrees = 0; break; case ASM_EXPR: get_asm_expr_operands (local, t); *walk_subtrees = 0; break; default: break; } return NULL; }
static tree scan_for_static_refs (tree *tp, int *walk_subtrees, void *data) { struct cgraph_node *fn = (struct cgraph_node *) data; tree t = *tp; ipa_reference_local_vars_info_t local = NULL; if (fn) local = get_reference_vars_info_from_cgraph (fn)->local; switch (TREE_CODE (t)) { case VAR_DECL: if (DECL_INITIAL (t)) walk_tree (&DECL_INITIAL (t), scan_for_static_refs, fn, visited_nodes); *walk_subtrees = 0; break; case GIMPLE_MODIFY_STMT: { /* First look on the lhs and see what variable is stored to */ tree lhs = GIMPLE_STMT_OPERAND (t, 0); tree rhs = GIMPLE_STMT_OPERAND (t, 1); check_lhs_var (local, lhs); /* For the purposes of figuring out what the cast affects */ /* Next check the operands on the rhs to see if they are ok. */ switch (TREE_CODE_CLASS (TREE_CODE (rhs))) { case tcc_binary: case tcc_comparison: { tree op0 = TREE_OPERAND (rhs, 0); tree op1 = TREE_OPERAND (rhs, 1); check_rhs_var (local, op0); check_rhs_var (local, op1); } break; case tcc_unary: { tree op0 = TREE_OPERAND (rhs, 0); check_rhs_var (local, op0); } break; case tcc_reference: check_rhs_var (local, rhs); break; case tcc_declaration: check_rhs_var (local, rhs); break; case tcc_expression: switch (TREE_CODE (rhs)) { case ADDR_EXPR: check_rhs_var (local, rhs); break; default: break; } break; case tcc_vl_exp: switch (TREE_CODE (rhs)) { case CALL_EXPR: check_call (local, rhs); break; default: break; } break; default: break; } *walk_subtrees = 0; } break; case ADDR_EXPR: /* This case is here to find addresses on rhs of constructors in decl_initial of static variables. */ check_rhs_var (local, t); *walk_subtrees = 0; break; case LABEL_EXPR: if (DECL_NONLOCAL (TREE_OPERAND (t, 0))) { /* Target of long jump. */ local->calls_read_all = true; local->calls_write_all = true; } break; case CALL_EXPR: check_call (local, t); *walk_subtrees = 0; break; case ASM_EXPR: get_asm_expr_operands (local, t); *walk_subtrees = 0; break; default: break; } return NULL; }