+/**
+ * Analyse a Call address.
+ *
+ * @param node the node representing the call address
+ * @param methods after call contains the set of all possibly called entities
+ */
+static void callee_ana_node(ir_node *node, eset *methods) {
+ int i;
+
+ assert(mode_is_reference(get_irn_mode(node)) || is_Bad(node));
+ /* Beware of recursion */
+ if (get_irn_link(node) == MARK) {
+ /* already visited */
+ return;
+ }
+ set_irn_link(node, MARK);
+
+ switch (get_irn_opcode(node)) {
+ case iro_Const:
+ /* A direct address call. We tread this as an external
+ call and ignore it completely. */
+ eset_insert(methods, MARK); /* free method -> unknown */
+ break;
+ case iro_SymConst:
+ if (get_SymConst_kind(node) == symconst_addr_ent) {
+ ir_entity *ent = get_SymConst_entity(node);
+ assert(ent && is_Method_type(get_entity_type(ent)));
+ eset_insert(methods, ent);
+ } else {
+ assert(get_SymConst_kind(node) == symconst_addr_name);
+ /* externe Methode (wegen fix_symconst!) */
+ eset_insert(methods, MARK); /* free method -> unknown */
+ }
+ break;
+ case iro_Sel:
+ /* polymorphe Methode */
+ for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
+ ir_entity * ent = get_Sel_method(node, i);
+ if (ent) {
+ eset_insert(methods, ent);
+ } else {
+ eset_insert(methods, MARK);
+ }
+ }
+ break;
+
+ case iro_Bad:
+ /* nothing */
+ break;
+
+ case iro_Phi:
+ for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
+ callee_ana_node(get_Phi_pred(node, i), methods);
+ }
+ break;
+
+ case iro_Mux:
+ callee_ana_node(get_Mux_false(node), methods);
+ callee_ana_node(get_Mux_true(node), methods);
+ break;
+
+ case iro_Psi:
+ for (i = get_Psi_n_conds(node) - 1; i >= 0; --i) {
+ callee_ana_node(get_Psi_val(node, i), methods);
+ }
+ callee_ana_node(get_Psi_default(node), methods);
+ break;
+
+ case iro_Id:
+ callee_ana_node(get_Id_pred(node), methods);
+ break;
+
+ case iro_Proj:
+ callee_ana_proj(get_Proj_pred(node), get_Proj_proj(node), methods);
+ break;
+
+ case iro_Add:
+ case iro_Sub:
+ case iro_Conv:
+ /* extern */
+ eset_insert(methods, MARK); /* free method -> unknown */
+ break;
+
+ default:
+ assert(0 && "invalid opcode or opcode not implemented");
+ break;
+ }
+
+ set_irn_link(node, NULL);
+}