introduce Switch node
authorMatthias Braun <matze@braunis.de>
Wed, 2 Nov 2011 17:57:20 +0000 (18:57 +0100)
committerMatthias Braun <matze@braunis.de>
Wed, 2 Nov 2011 19:00:48 +0000 (20:00 +0100)
This is the new way of handling switch-jumps. The node contains a table
which maps (ranges of) input values to proj numbers. Compared to a
Cond-node this results in a clean consecutive sequence of Proj numbers
(no searching for a free number for the default_pn anymore) and allows
factoring multiple cases jumping to the same block in a single Proj
(though we still need the optimisation in cfopt for that).

38 files changed:
include/libfirm/firm_types.h
include/libfirm/irnode.h
ir/ana/irconsconfirm.c
ir/be/arm/arm_emitter.c
ir/be/arm/arm_new_nodes.c
ir/be/arm/arm_new_nodes.h
ir/be/arm/arm_nodes_attr.h
ir/be/arm/arm_spec.pl
ir/be/arm/arm_transform.c
ir/be/arm/bearch_arm.c
ir/be/begnuas.c
ir/be/begnuas.h
ir/be/ia32/ia32_emitter.c
ir/be/ia32/ia32_new_nodes.c
ir/be/ia32/ia32_new_nodes.h
ir/be/ia32/ia32_nodes_attr.h
ir/be/ia32/ia32_spec.pl
ir/be/ia32/ia32_transform.c
ir/be/sparc/sparc_emitter.c
ir/be/sparc/sparc_new_nodes.c
ir/be/sparc/sparc_nodes_attr.h
ir/be/sparc/sparc_spec.pl
ir/be/sparc/sparc_transform.c
ir/ir/irdump.c
ir/ir/irdumptxt.c
ir/ir/irnode.c
ir/ir/irnode_t.h
ir/ir/irop.c
ir/ir/iropt.c
ir/ir/irtypes.h
ir/ir/irverify.c
ir/lower/lower_dw.c
ir/lower/lower_switch.c
ir/opt/cfopt.c
ir/opt/combo.c
ir/opt/fp-vrp.c
ir/opt/jumpthreading.c
scripts/ir_spec.py

index 5649eeb..6a73801 100644 (file)
@@ -64,6 +64,13 @@ typedef union  ir_initializer_t     ir_initializer_t,    *ir_initializer_ptr;
 typedef void irg_walk_func(ir_node *, void *);
 typedef void irg_reg_walk_func(ir_region *, void *);
 
+/**
+ * A switch table mapping integer numbers to proj-numbers of a Switch-node.
+ * Entries map a continuous range of integer numbers to a proj-number.
+ * There must never be two different entries matching the same integer number.
+ */
+typedef struct ir_switch_table  ir_switch_table;
+
 /* Needed for MSVC to suppress warnings because it doest NOT handle const right. */
 typedef const ir_node *ir_node_cnst_ptr;
 
index 1c0a96a..69c1d37 100644 (file)
@@ -727,6 +727,23 @@ FIRM_API unsigned firm_default_hash(const ir_node *node);
  */
 FIRM_API const char *gdb_node_helper(void *firm_object);
 
+FIRM_API ir_switch_table *ir_new_switch_table(ir_graph *irg, size_t n_entries);
+
+FIRM_API size_t ir_switch_table_get_n_entries(const ir_switch_table *table);
+
+FIRM_API void ir_switch_table_set(ir_switch_table *table, size_t entry,
+                                  ir_tarval *min, ir_tarval *max, long pn);
+
+FIRM_API ir_tarval *ir_switch_table_get_max(const ir_switch_table *table,
+                                            size_t entry);
+
+FIRM_API ir_tarval *ir_switch_table_get_min(const ir_switch_table *table,
+                                            size_t entry);
+
+FIRM_API long ir_switch_table_get_pn(const ir_switch_table *table, size_t entry);
+
+FIRM_API ir_switch_table *ir_switch_table_duplicate(ir_graph *irg, const ir_switch_table *table);
+
 /*@}*/
 
 #include "end.h"
index 237b992..faabd52 100644 (file)
@@ -41,6 +41,7 @@
 #include "irtools.h"
 #include "array_t.h"
 #include "debug.h"
+#include "error.h"
 #include "irflag.h"
 
 /**
@@ -75,32 +76,53 @@ static ir_node *get_effective_use_block(ir_node *node, int pos)
        return get_nodes_block(node);
 }
 
+static ir_node *get_case_value(ir_node *switchn, long pn)
+{
+       ir_graph              *irg       = get_irn_irg(switchn);
+       const ir_switch_table *table     = get_Switch_table(switchn);
+       size_t                 n_entries = ir_switch_table_get_n_entries(table);
+       ir_tarval             *val       = NULL;
+       size_t                 e;
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               if (entry->pn != pn)
+                       continue;
+               /* multiple matching entries gets too complicated for a single
+                * Confirm */
+               if (val != NULL)
+                       return NULL;
+               /* case ranges are too complicated too */
+               if (entry->min != entry->max)
+                       return NULL;
+               val = entry->min;
+       }
+       assert(val != NULL);
+       return new_r_Const(irg, val);
+}
+
 /**
  * Handle a CASE-branch.
  *
- * @param block   the block which is entered by the branch
- * @param irn     the node expressing the switch value
- * @param nr      the branch label
- * @param env     statistical environment
- *
  * Branch labels are a simple case. We can replace the value
  * by a Const with the branch label.
  */
-static void handle_case(ir_node *block, ir_node *irn, long nr, env_t *env)
+static void handle_case(ir_node *block, ir_node *switchn, long pn, env_t *env)
 {
-       const ir_edge_t *edge, *next;
-       ir_node *c = NULL;
+       ir_node         *c = NULL;
+       ir_node         *selector = get_Switch_selector(switchn);
+       const ir_edge_t *edge;
+       const ir_edge_t *next;
 
-       if (is_Bad(irn))
+       /* we can't do usefull things with the default label */
+       if (pn == pn_Switch_default)
                return;
 
-       for (edge = get_irn_out_edge_first(irn); edge; edge = next) {
+       foreach_out_edge_safe(selector, edge, next) {
                ir_node *succ = get_edge_src_irn(edge);
                int     pos   = get_edge_src_pos(edge);
                ir_node *blk  = get_effective_use_block(succ, pos);
 
-               next = get_irn_out_edge_next(irn, edge);
-
                if (block_dominates(block, blk)) {
                        /*
                         * Ok, we found a user of irn that is placed
@@ -108,15 +130,11 @@ static void handle_case(ir_node *block, ir_node *irn, long nr, env_t *env)
                         * We can replace the input with the Constant
                         * branch label.
                         */
-
-                       if (! c) {
-                               ir_mode   *mode = get_irn_mode(irn);
-                               ir_tarval *tv   = new_tarval_from_long(nr, mode);
-                               c = new_r_Const(current_ir_graph, tv);
-                       }
+                       if (c == NULL)
+                               c = get_case_value(switchn, pn);
 
                        set_irn_n(succ, pos, c);
-                       DBG_OPT_CONFIRM_C(irn, c);
+                       DBG_OPT_CONFIRM_C(selector, c);
                        DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
 
                        env->num_consts += 1;
@@ -405,9 +423,9 @@ static void handle_if(ir_node *block, ir_node *cmp, ir_relation rel, env_t *env)
  */
 static void insert_Confirm_in_block(ir_node *block, void *data)
 {
-       ir_node *cond, *proj, *selector;
-       ir_mode *mode;
        env_t   *env = (env_t*) data;
+       ir_node *cond;
+       ir_node *proj;
 
        /*
         * we can only handle blocks with only ONE control flow
@@ -421,13 +439,11 @@ static void insert_Confirm_in_block(ir_node *block, void *data)
                return;
 
        cond = get_Proj_pred(proj);
-       if (! is_Cond(cond))
-               return;
-
-       selector = get_Cond_selector(cond);
-       mode = get_irn_mode(selector);
-
-       if (mode == mode_b) {
+       if (is_Switch(cond)) {
+               long proj_nr = get_Proj_proj(proj);
+               handle_case(block, cond, proj_nr, env);
+       } else if (is_Const(cond)) {
+               ir_node *selector = get_Cond_selector(cond);
                ir_relation rel;
 
                handle_modeb(block, selector, (pn_Cond) get_Proj_proj(proj), env);
@@ -439,20 +455,11 @@ static void insert_Confirm_in_block(ir_node *block, void *data)
 
                if (get_Proj_proj(proj) != pn_Cond_true) {
                        /* it's the false branch */
-                       mode = get_irn_mode(get_Cmp_left(selector));
                        rel = get_negated_relation(rel);
                }
                DB((dbg, LEVEL_2, "At %+F using %+F Confirm %=\n", block, selector, rel));
 
                handle_if(block, selector, rel, env);
-       } else if (mode_is_int(mode)) {
-               long proj_nr = get_Proj_proj(proj);
-
-               /* this is a CASE, but we cannot handle the default case */
-               if (proj_nr == get_Cond_default_proj(cond))
-                       return;
-
-               handle_case(block, get_Cond_selector(cond), proj_nr, env);
        }
 }
 
index 85f3abb..6a23d7a 100644 (file)
@@ -579,80 +579,13 @@ static void emit_arm_CopyB(const ir_node *irn)
 
 static void emit_arm_SwitchJmp(const ir_node *irn)
 {
-       const ir_edge_t    *edge;
-       ir_node            *proj;
-       int i;
-       ir_node **projs;
-       int n_projs;
-       int block_nr;
-       ir_node *default_proj = NULL;
-
-       block_nr = get_irn_node_nr(irn);
-       n_projs = get_arm_SwitchJmp_n_projs(irn);
-
-       projs = XMALLOCNZ(ir_node*, n_projs);
-
-       foreach_out_edge(irn, edge) {
-               proj = get_edge_src_irn(edge);
-               assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
-
-               if (get_Proj_proj(proj) == get_arm_SwitchJmp_default_proj_num(irn))
-                       default_proj = proj;
-
-               projs[get_Proj_proj(proj)] = proj;
-       }
-       assert(default_proj != NULL && "SwitchJmp should have a Default Proj");
-
-       /*
-          CMP %1S, n_projs - 1
-          BHI default
-       */
-
-       be_emit_cstring("\tcmp ");
+       const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
+       be_emit_cstring("\tldrls pc, [pc, ");
        arm_emit_source_register(irn, 0);
-       be_emit_irprintf(", #%u", n_projs - 1);
+       be_emit_cstring(", asl #2]");
        be_emit_finish_line_gas(irn);
 
-       be_emit_cstring("\tbhi ");
-       arm_emit_cfop_target(default_proj);
-       be_emit_finish_line_gas(default_proj);
-
-       /*
-          LDR %r12, .TABLE_X_START
-          ADD %r12, %r12, [%1S, LSL #2]
-          LDR %r15, %r12
-        */
-
-       be_emit_irprintf("\tldr %%r12, TABLE_%d_START", block_nr);
-       be_emit_finish_line_gas(NULL);
-
-       be_emit_irprintf("\tadd %%r12, %%r12, ");
-       arm_emit_source_register(irn, 0);
-       be_emit_cstring(", LSL #2");
-       be_emit_finish_line_gas(NULL);
-
-       be_emit_cstring("\tldr %r15, [%r12, #0]");
-       be_emit_finish_line_gas(NULL);
-
-       be_emit_irprintf("TABLE_%d_START:\n\t.word\tTABLE_%d", block_nr, block_nr);
-       be_emit_finish_line_gas(NULL);
-       be_emit_irprintf("\t.align 2");
-       be_emit_finish_line_gas(NULL);
-       be_emit_irprintf("TABLE_%d:", block_nr);
-       be_emit_finish_line_gas(NULL);
-
-       for (i = 0; i < n_projs; ++i) {
-               proj = projs[i];
-               if (proj == NULL) {
-                       proj = projs[get_arm_SwitchJmp_default_proj_num(irn)];
-               }
-               be_emit_cstring("\t.word\t");
-               arm_emit_cfop_target(proj);
-               be_emit_finish_line_gas(proj);
-       }
-       be_emit_irprintf("\t.align 2\n");
-       be_emit_finish_line_gas(NULL);
-       xfree(projs);
+       be_emit_jump_table(irn, attr->table, NULL, get_cfop_target_block);
 }
 
 /** Emit an IncSP node */
index 9f805fe..d8bb7d0 100644 (file)
@@ -324,30 +324,6 @@ void set_arm_CondJmp_relation(ir_node *node, ir_relation relation)
        attr->relation = relation;
 }
 
-int get_arm_SwitchJmp_n_projs(const ir_node *node)
-{
-       const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(node);
-       return attr->n_projs;
-}
-
-void set_arm_SwitchJmp_n_projs(ir_node *node, int n_projs)
-{
-       arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr(node);
-       attr->n_projs = n_projs;
-}
-
-long get_arm_SwitchJmp_default_proj_num(const ir_node *node)
-{
-       const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(node);
-       return attr->default_proj_num;
-}
-
-void set_arm_SwitchJmp_default_proj_num(ir_node *node, long default_proj_num)
-{
-       arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr(node);
-       attr->default_proj_num = default_proj_num;
-}
-
 /* Set the ARM machine node attributes to default values. */
 static void init_arm_attributes(ir_node *node, arch_irn_flags_t flags,
                          const arch_register_req_t ** in_reqs,
@@ -420,6 +396,20 @@ static void init_arm_CopyB_attributes(ir_node *res, unsigned size)
        attr->size = size;
 }
 
+static void init_arm_SwitchJmp_attributes(ir_node *res,
+                                          const ir_switch_table *table)
+{
+       unsigned n_outs = arch_get_irn_n_outs(res);
+       unsigned o;
+
+       arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr(res);
+       attr->table = table;
+
+       for (o = 0; o < n_outs; ++o) {
+               arch_set_irn_register_req_out(res, o, arch_no_register_req);
+       }
+}
+
 static int cmp_attr_arm(const ir_node *a, const ir_node *b)
 {
        (void) a;
index fd9c083..e5775a9 100644 (file)
@@ -91,26 +91,6 @@ void set_arm_CondJmp_relation(ir_node *node, ir_relation relation);
 ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, ir_node *sp,
                                                              int n_regs, ir_node **regs, ir_mode *mode);
 
-/**
- * Returns the number of projs of a SwitchJmp.
- */
-int get_arm_SwitchJmp_n_projs(const ir_node *node);
-
-/**
- * Sets the number of projs of a SwitchJmp.
- */
-void set_arm_SwitchJmp_n_projs(ir_node *node, int n_projs);
-
-/**
- * Returns the default_proj_num.
- */
-long get_arm_SwitchJmp_default_proj_num(const ir_node *node);
-
-/**
- * Sets the default_proj_num.
- */
-void set_arm_SwitchJmp_default_proj_num(ir_node *node, long default_proj_num);
-
 /* Include the generated headers */
 #include "gen_arm_new_nodes.h"
 
index 778f986..7b202fa 100644 (file)
@@ -112,9 +112,8 @@ typedef struct arm_CondJmp_attr_t {
 
 /** Attributes for a SwitchJmp */
 typedef struct arm_SwitchJmp_attr_t {
-       arm_attr_t  base;
-       int         n_projs;
-       long        default_proj_num;
+       arm_attr_t             base;
+       const ir_switch_table *table;
 } arm_SwitchJmp_attr_t;
 
 /** CopyB attributes */
index 39419ff..c399815 100644 (file)
@@ -415,11 +415,10 @@ SwitchJmp => {
        op_flags  => [ "labeled", "cfopcode", "forking" ],
        state     => "pinned",
        mode      => "mode_T",
-       attr      => "int n_projs, long def_proj_num",
-       init_attr => "\tset_arm_SwitchJmp_n_projs(res, n_projs);\n".
-                    "\tset_arm_SwitchJmp_default_proj_num(res, def_proj_num);\n".
-                    "\tinfo->out_infos = NULL;",
+       attr      => "const ir_switch_table *table",
+       init_attr => "init_arm_SwitchJmp_attributes(res, table);",
        reg_req   => { in => [ "gp" ], out => [ "none" ] },
+       out_arity => "variable",
        attr_type => "arm_SwitchJmp_attr_t",
 },
 
index ea859a3..a81ce5a 100644 (file)
@@ -1013,46 +1013,23 @@ static ir_node *gen_Jmp(ir_node *node)
        return new_bd_arm_Jmp(dbgi, new_block);
 }
 
-static ir_node *gen_SwitchJmp(ir_node *node)
+static ir_node *gen_Switch(ir_node *node)
 {
-       ir_node  *block    = be_transform_node(get_nodes_block(node));
-       ir_node  *selector = get_Cond_selector(node);
-       dbg_info *dbgi     = get_irn_dbg_info(node);
-       ir_node *new_op = be_transform_node(selector);
-       ir_node *const_graph;
-       ir_node *sub;
-
-       ir_node *proj;
-       const ir_edge_t *edge;
-       int min = INT_MAX;
-       int max = INT_MIN;
-       int translation;
-       int pn;
-       int n_projs;
+       ir_graph              *irg      = get_irn_irg(node);
+       ir_node               *block    = be_transform_node(get_nodes_block(node));
+       ir_node               *selector = get_Switch_selector(node);
+       dbg_info              *dbgi     = get_irn_dbg_info(node);
+       ir_node               *new_op   = be_transform_node(selector);
+       ir_mode               *mode     = get_irn_mode(selector);
+       const ir_switch_table *table    = get_Switch_table(node);
+       unsigned               n_outs   = get_Switch_n_outs(node);
 
-       foreach_out_edge(node, edge) {
-               proj = get_edge_src_irn(edge);
-               assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
+       table = ir_switch_table_duplicate(irg, table);
 
-               pn = get_Proj_proj(proj);
-
-               min = pn<min ? pn : min;
-               max = pn>max ? pn : max;
-       }
-       translation = min;
-       n_projs = max - translation + 1;
+       /* switch with smaller modes not implemented yet */
+       assert(get_mode_size_bits(mode) == 32);
 
-       foreach_out_edge(node, edge) {
-               proj = get_edge_src_irn(edge);
-               assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
-
-               pn = get_Proj_proj(proj) - translation;
-               set_Proj_proj(proj, pn);
-       }
-
-       const_graph = create_const_graph_value(dbgi, block, translation);
-       sub = new_bd_arm_Sub_reg(dbgi, block, new_op, const_graph);
-       return new_bd_arm_SwitchJmp(dbgi, block, sub, n_projs, get_Cond_default_proj(node) - translation);
+       return new_bd_arm_SwitchJmp(dbgi, block, new_op, n_outs, table);
 }
 
 static ir_node *gen_Cmp(ir_node *node)
@@ -1089,15 +1066,11 @@ static ir_node *gen_Cmp(ir_node *node)
 static ir_node *gen_Cond(ir_node *node)
 {
        ir_node    *selector = get_Cond_selector(node);
-       ir_mode    *mode     = get_irn_mode(selector);
        ir_relation relation;
        ir_node    *block;
        ir_node    *flag_node;
        dbg_info   *dbgi;
 
-       if (mode != mode_b) {
-               return gen_SwitchJmp(node);
-       }
        assert(is_Cmp(selector));
 
        block     = be_transform_node(get_nodes_block(node));
@@ -1612,6 +1585,7 @@ static ir_node *gen_Proj(ir_node *node)
        case iro_Start:
                return gen_Proj_Start(node);
        case iro_Cond:
+       case iro_Switch:
                /* nothing to do */
                return be_duplicate_node(node);
        case iro_Proj: {
@@ -2102,6 +2076,7 @@ static void arm_register_transformers(void)
        be_set_transform_function(op_Start,    gen_Start);
        be_set_transform_function(op_Store,    gen_Store);
        be_set_transform_function(op_Sub,      gen_Sub);
+       be_set_transform_function(op_Switch,   gen_Switch);
        be_set_transform_function(op_SymConst, gen_SymConst);
        be_set_transform_function(op_Unknown,  gen_Unknown);
        be_set_transform_function(op_Builtin,  gen_Builtin);
index a93d3be..838e31a 100644 (file)
@@ -541,7 +541,7 @@ static void arm_lower_for_target(void)
 
        for (i = 0; i < n_irgs; ++i) {
                ir_graph *irg = get_irp_irg(i);
-               lower_switch(irg, 4, 256, true);
+               lower_switch(irg, 4, 256, false);
        }
 
        for (i = 0; i < n_irgs; ++i) {
index d72e74e..16f62a5 100644 (file)
@@ -1720,66 +1720,101 @@ static void emit_global_decls(const be_main_env_t *main_env)
        }
 }
 
-void emit_jump_table(const ir_node *node, long default_pn, ir_entity *entity,
-                     get_cfop_target_func get_cfop_target)
+void be_emit_jump_table(const ir_node *node, const ir_switch_table *table,
+                        ir_entity *entity, get_cfop_target_func get_cfop_target)
 {
-       long             switch_max    = LONG_MIN;
-       ir_node         *default_block = NULL;
-       unsigned long    length;
-       const ir_edge_t *edge;
-       unsigned         i;
-       ir_node        **table;
-
-       /* go over all proj's and collect them */
+       unsigned          n_outs    = arch_get_irn_n_outs(node);
+       const ir_node   **targets   = XMALLOCNZ(const ir_node*, n_outs);
+       size_t            n_entries = ir_switch_table_get_n_entries(table);
+       unsigned long     length    = 0;
+       size_t            e;
+       const ir_edge_t  *edge;
+       unsigned          i;
+       const ir_node   **labels;
+
+       /* go over all proj's and collect their jump targets */
        foreach_out_edge(node, edge) {
-               ir_node *proj = get_edge_src_irn(edge);
-               long     pn   = get_Proj_proj(proj);
-
-               /* check for default proj */
-               if (pn == default_pn) {
-                       assert(default_block == NULL); /* more than 1 default_pn? */
-                       default_block = get_cfop_target(proj);
-               } else {
-                       switch_max = pn > switch_max ? pn : switch_max;
+               ir_node *proj   = get_edge_src_irn(edge);
+               long     pn     = get_Proj_proj(proj);
+               ir_node *target = get_cfop_target(proj);
+               assert(targets[pn] == NULL);
+               targets[pn] = target;
+       }
+
+       /* go over table to determine max value (note that we normalized the
+        * ranges so that the minimum is 0) */
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               ir_tarval *max = entry->max;
+               unsigned long val;
+               if (entry->pn == 0)
+                       continue;
+               if (!tarval_is_long(max))
+                       panic("switch case overflow (%+F)", node);
+               val = (unsigned long) get_tarval_long(max);
+               if (val > length) {
+                       length = val;
                }
        }
-       assert(switch_max > LONG_MIN);
 
-       length = (unsigned long) switch_max + 1;
        /* the 16000 isn't a real limit of the architecture. But should protect us
         * from seamingly endless compiler runs */
        if (length > 16000) {
                /* switch lowerer should have broken this monster to pieces... */
-               panic("too large switch encountered");
+               panic("too large switch encountered (%+F)", node);
+       }
+       ++length;
+
+       labels = XMALLOCNZ(const ir_node*, length);
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               ir_tarval     *min    = entry->min;
+               ir_tarval     *max    = entry->max;
+               const ir_node *target = targets[entry->pn];
+               assert(entry->pn < (long)n_outs);
+               if (min == max) {
+                       unsigned long val = (unsigned long)get_tarval_long(max);
+                       labels[val] = target;
+               } else {
+                       unsigned long min_val;
+                       unsigned long max_val;
+                       unsigned long i;
+                       if (!tarval_is_long(min))
+                               panic("switch case overflow (%+F)", node);
+                       min_val = (unsigned long)get_tarval_long(min);
+                       max_val = (unsigned long)get_tarval_long(max);
+                       assert(min_val <= max_val);
+                       for (i = min_val; i <= max_val; ++i) {
+                               labels[i] = target;
+                       }
+               }
        }
 
-       table = XMALLOCNZ(ir_node*, length);
-       foreach_out_edge(node, edge) {
-               ir_node *proj = get_edge_src_irn(edge);
-               long     pn   = get_Proj_proj(proj);
-               if (pn == default_pn)
-                       continue;
-
-               table[pn] = get_cfop_target(proj);
+       /* emit table */
+       if (entity != NULL) {
+               be_gas_emit_switch_section(GAS_SECTION_RODATA);
+               be_emit_cstring("\t.align 4\n");
+               be_gas_emit_entity(entity);
+               be_emit_cstring(":\n");
        }
 
-       /* emit table */
-       be_gas_emit_switch_section(GAS_SECTION_RODATA);
-       be_emit_cstring("\t.align 4\n");
-       be_gas_emit_entity(entity);
-       be_emit_cstring(":\n");
        for (i = 0; i < length; ++i) {
-               ir_node *block = table[i];
+               const ir_node *block = labels[i];
                if (block == NULL)
-                       block = default_block;
+                       block = targets[0];
                be_emit_cstring("\t.long ");
                be_gas_emit_block_name(block);
                be_emit_char('\n');
                be_emit_write_line();
        }
-       be_gas_emit_switch_section(GAS_SECTION_TEXT);
 
-       xfree(table);
+       if (entity != NULL)
+               be_gas_emit_switch_section(GAS_SECTION_TEXT);
+
+       xfree(labels);
+       xfree(targets);
 }
 
 static void emit_global_asms(void)
index 45c05c2..5b5bf91 100644 (file)
@@ -129,7 +129,8 @@ typedef ir_node* (*get_cfop_target_func)(const ir_node *cfop);
 /**
  * Emits a jump table for switch operations
  */
-void emit_jump_table(const ir_node *node, long default_pn, ir_entity *table,
-                     get_cfop_target_func get_cfop_target);
+void be_emit_jump_table(const ir_node *node, const ir_switch_table *table,
+                        ir_entity *entity,
+                        get_cfop_target_func get_cfop_target);
 
 #endif
index 628edf3..f7adac3 100644 (file)
@@ -1066,11 +1066,11 @@ static void emit_ia32_CMovcc(const ir_node *node)
  */
 static void emit_ia32_SwitchJmp(const ir_node *node)
 {
-       ir_entity *jump_table = get_ia32_am_sc(node);
-       long       default_pn = get_ia32_default_pn(node);
+       ir_entity             *jump_table = get_ia32_am_sc(node);
+       const ir_switch_table *table      = get_ia32_switch_table(node);
 
        ia32_emitf(node, "\tjmp %*AM\n");
-       emit_jump_table(node, default_pn, jump_table, get_cfop_target_block);
+       be_emit_jump_table(node, table, jump_table, get_cfop_target_block);
 }
 
 /**
@@ -3220,13 +3220,13 @@ static void bemit_ia32_jcc(const ir_node *node)
 
 static void bemit_switchjmp(const ir_node *node)
 {
-       ir_entity *jump_table = get_ia32_am_sc(node);
-       long       default_pn = get_ia32_default_pn(node);
+       ir_entity             *jump_table = get_ia32_am_sc(node);
+       const ir_switch_table *table      = get_ia32_switch_table(node);
 
        bemit8(0xFF); // jmp *tbl.label(,%in,4)
        bemit_mod_am(0x05, node);
 
-       emit_jump_table(node, default_pn, jump_table, get_cfop_target_block);
+       be_emit_jump_table(node, table, jump_table, get_cfop_target_block);
 }
 
 /**
index 81bea2c..ddfd4df 100644 (file)
@@ -185,9 +185,7 @@ static void ia32_dump_node(FILE *F, ir_node *n, dump_reason_t reason)
                        fprintf(F, "AM scale = %u\n", get_ia32_am_scale(n));
 
                        /* dump pn code */
-                       if (is_ia32_SwitchJmp(n)) {
-                               fprintf(F, "default_pn = %ld\n", get_ia32_default_pn(n));
-                       } else if (is_ia32_CMovcc(n) || is_ia32_Setcc(n) || is_ia32_Jcc(n)) {
+                       if (is_ia32_CMovcc(n) || is_ia32_Setcc(n) || is_ia32_Jcc(n)) {
                                ia32_attr_t *attr = get_ia32_attr(n);
                                fprintf(F, "condition_code = 0x%X\n", (unsigned)get_ia32_condcode(n));
                                fprintf(F, "ins_permuted = %u\n", (unsigned)attr->data.ins_permuted);
@@ -673,9 +671,12 @@ unsigned get_ia32_latency(const ir_node *node)
        return op_attr->latency;
 }
 
-/**
- * Returns the condition code of a node.
- */
+const ir_switch_table *get_ia32_switch_table(const ir_node *node)
+{
+       const ia32_switch_attr_t *attr = get_ia32_switch_attr_const(node);
+       return attr->table;
+}
+
 ia32_condition_code_t get_ia32_condcode(const ir_node *node)
 {
        const ia32_condcode_attr_t *attr = get_ia32_condcode_attr_const(node);
@@ -691,12 +692,6 @@ void set_ia32_condcode(ir_node *node, ia32_condition_code_t code)
        attr->condition_code = code;
 }
 
-long get_ia32_default_pn(const ir_node *node)
-{
-       const ia32_switch_attr_t *attr = get_ia32_switch_attr_const(node);
-       return attr->default_pn;
-}
-
 /**
  * Returns the condition code of a node.
  */
@@ -926,15 +921,22 @@ static void init_ia32_climbframe_attributes(ir_node *res, unsigned count)
        attr->count = count;
 }
 
-static void init_ia32_switch_attributes(ir_node *res, long default_pn)
+static void init_ia32_switch_attributes(ir_node *node,
+                                        const ir_switch_table *table)
 {
-       ia32_switch_attr_t *attr = (ia32_switch_attr_t*) get_irn_generic_attr(res);
+       unsigned n_outs = arch_get_irn_n_outs(node);
+       unsigned o;
+
+       ia32_switch_attr_t *attr = (ia32_switch_attr_t*) get_irn_generic_attr(node);
 #ifndef NDEBUG
        attr->attr.attr_type |= IA32_ATTR_ia32_switch_attr_t;
 #endif
-       attr->default_pn = default_pn;
-}
+       attr->table = table;
 
+       for (o = 0; o < n_outs; ++o) {
+               arch_set_irn_register_req_out(node, o, arch_no_register_req);
+       }
+}
 
 /* default compare operation to compare attributes */
 static int ia32_compare_attr(const ia32_attr_t *a, const ia32_attr_t *b)
@@ -997,24 +999,6 @@ static int ia32_compare_condcode_attr(const ir_node *a, const ir_node *b)
        return 0;
 }
 
-/** Compare node attributes for nodes with condition code. */
-static int ia32_compare_switch_attr(const ir_node *a, const ir_node *b)
-{
-       const ia32_switch_attr_t *attr_a;
-       const ia32_switch_attr_t *attr_b;
-
-       if (ia32_compare_nodes_attr(a, b))
-               return 1;
-
-       attr_a = get_ia32_switch_attr_const(a);
-       attr_b = get_ia32_switch_attr_const(b);
-
-       if (attr_a->default_pn != attr_b->default_pn)
-               return 1;
-
-       return 0;
-}
-
 /** Compare node attributes for call nodes. */
 static int ia32_compare_call_attr(const ir_node *a, const ir_node *b)
 {
index 8fb8f44..aa48fdc 100644 (file)
@@ -256,7 +256,7 @@ ia32_condition_code_t get_ia32_condcode(const ir_node *node);
  */
 void set_ia32_condcode(ir_node *node, ia32_condition_code_t code);
 
-long get_ia32_default_pn(const ir_node *node);
+const ir_switch_table *get_ia32_switch_table(const ir_node *node);
 
 unsigned get_ia32_copyb_size(const ir_node *node);
 
index 1e8844e..0673939 100644 (file)
@@ -235,9 +235,9 @@ struct ia32_condcode_attr_t {
  */
 typedef struct ia32_switch_attr_t ia32_switch_attr_t;
 struct ia32_switch_attr_t {
-       ia32_attr_t  attr;        /**< generic attribute */
-       long         default_pn;
-       ir_entity   *jump_table;
+       ia32_attr_t            attr;        /**< generic attribute */
+       const ir_switch_table *table;
+       ir_entity             *jump_table;
 };
 
 /**
index a939448..bdf1a44 100644 (file)
@@ -185,7 +185,7 @@ $custom_init_attr_func = \&ia32_custom_init_attr;
                "\tinit_ia32_condcode_attributes(res, condition_code);",
        ia32_switch_attr_t =>
                "\tinit_ia32_attributes(res, irn_flags_, in_reqs, exec_units, n_res);\n".
-               "\tinit_ia32_switch_attributes(res, default_pn);",
+               "\tinit_ia32_switch_attributes(res, switch_table);",
        ia32_copyb_attr_t =>
                "\tinit_ia32_attributes(res, irn_flags_, in_reqs, exec_units, n_res);\n".
                "\tinit_ia32_copyb_attributes(res, size);",
@@ -205,8 +205,8 @@ $custom_init_attr_func = \&ia32_custom_init_attr;
        ia32_attr_t            => "ia32_compare_nodes_attr",
        ia32_call_attr_t       => "ia32_compare_call_attr",
        ia32_condcode_attr_t   => "ia32_compare_condcode_attr",
-       ia32_switch_attr_t     => "ia32_compare_switch_attr",
        ia32_copyb_attr_t      => "ia32_compare_copyb_attr",
+       ia32_switch_attr_t     => "ia32_compare_nodes_attr",
        ia32_immediate_attr_t  => "ia32_compare_immediate_attr",
        ia32_x87_attr_t        => "ia32_compare_x87_attr",
        ia32_climbframe_attr_t => "ia32_compare_climbframe_attr",
@@ -1044,12 +1044,11 @@ SwitchJmp => {
        op_flags  => [ "labeled", "cfopcode", "forking" ],
        reg_req   => { in => [ "gp", "gp" ] },
        ins       => [ "base", "index" ],
-       mode      => "mode_T",
+       out_arity => "variable",
        attr_type => "ia32_switch_attr_t",
-       attr      => "long default_pn",
+       attr      => "const ir_switch_table *switch_table",
        latency   => 2,
        units     => [ "BRANCH" ],
-       init_attr => "info->out_infos = NULL;", # XXX ugly hack for out requirements
 },
 
 Jmp => {
index e5bc04d..3761d1b 100644 (file)
@@ -2756,26 +2756,30 @@ static ir_node *gen_Store(ir_node *node)
  *
  * @return the created ia32 SwitchJmp node
  */
-static ir_node *create_Switch(ir_node *node)
-{
-       dbg_info  *dbgi       = get_irn_dbg_info(node);
-       ir_node   *block      = be_transform_node(get_nodes_block(node));
-       ir_node   *sel        = get_Cond_selector(node);
-       ir_node   *new_sel    = be_transform_node(sel);
-       long       default_pn = get_Cond_default_proj(node);
-       ir_node   *new_node;
-       ir_entity *entity;
-
-       assert(get_mode_size_bits(get_irn_mode(sel)) == 32);
+static ir_node *gen_Switch(ir_node *node)
+{
+       dbg_info              *dbgi     = get_irn_dbg_info(node);
+       ir_graph              *irg      = get_irn_irg(node);
+       ir_node               *block    = be_transform_node(get_nodes_block(node));
+       ir_node               *sel      = get_Switch_selector(node);
+       ir_node               *new_sel  = be_transform_node(sel);
+       ir_mode               *sel_mode = get_irn_mode(sel);
+       const ir_switch_table *table    = get_Switch_table(node);
+       unsigned               n_outs   = get_Switch_n_outs(node);
+       ir_node               *new_node;
+       ir_entity             *entity;
+
+       assert(get_mode_size_bits(get_irn_mode(sel)) <= 32);
+       if (get_mode_size_bits(sel_mode) != 32)
+               new_sel = create_upconv(new_sel, sel);
 
        entity = new_entity(NULL, id_unique("TBL%u"), get_unknown_type());
        set_entity_visibility(entity, ir_visibility_private);
        add_entity_linkage(entity, IR_LINKAGE_CONSTANT);
 
-       /* TODO: we could perform some more matching here to also use the base
-        * register of the address mode */
-       new_node
-               = new_bd_ia32_SwitchJmp(dbgi, block, noreg_GP, new_sel, default_pn);
+       table = ir_switch_table_duplicate(irg, table);
+
+       new_node = new_bd_ia32_SwitchJmp(dbgi, block, noreg_GP, new_sel, n_outs, table);
        set_ia32_am_scale(new_node, 2);
        set_ia32_am_sc(new_node, entity);
        set_ia32_op_type(new_node, ia32_AddrModeS);
@@ -2796,15 +2800,10 @@ static ir_node *gen_Cond(ir_node *node)
        ir_node              *new_block = be_transform_node(block);
        dbg_info             *dbgi      = get_irn_dbg_info(node);
        ir_node              *sel       = get_Cond_selector(node);
-       ir_mode              *sel_mode  = get_irn_mode(sel);
        ir_node              *flags     = NULL;
        ir_node              *new_node;
        ia32_condition_code_t cc;
 
-       if (sel_mode != mode_b) {
-               return create_Switch(node);
-       }
-
        /* we get flags from a Cmp */
        flags = get_flags_node(sel, &cc);
 
@@ -5731,6 +5730,7 @@ static void register_transformers(void)
        be_set_transform_function(op_Shrs,             gen_Shrs);
        be_set_transform_function(op_Store,            gen_Store);
        be_set_transform_function(op_Sub,              gen_Sub);
+       be_set_transform_function(op_Switch,           gen_Switch);
        be_set_transform_function(op_SymConst,         gen_SymConst);
        be_set_transform_function(op_Unknown,          ia32_gen_Unknown);
 }
index 34a7165..c8fe24d 100644 (file)
@@ -1137,8 +1137,7 @@ static void emit_sparc_SwitchJmp(const ir_node *node)
        be_emit_finish_line_gas(node);
        fill_delay_slot();
 
-       emit_jump_table(node, attr->default_proj_num, attr->jump_table,
-                       get_jump_target);
+       be_emit_jump_table(node, attr->table, attr->table_entity, get_jump_target);
 }
 
 static void emit_fmov(const ir_node *node, const arch_register_t *src_reg,
index 5ae98a6..cb23385 100644 (file)
@@ -116,11 +116,6 @@ static void sparc_dump_node(FILE *F, ir_node *n, dump_reason_t reason)
                                get_relation_string(attr->relation));
                        fprintf(F, "unsigned: %s\n", attr->is_unsigned ? "true" : "false");
                }
-               if (has_switch_jmp_attr(n)) {
-                       const sparc_switch_jmp_attr_t *attr
-                               = get_sparc_switch_jmp_attr_const(n);
-                       fprintf(F, "default proj: %ld\n", attr->default_proj_num);
-               }
                if (has_fp_attr(n)) {
                        const sparc_fp_attr_t *attr = get_sparc_fp_attr_const(n);
                        ir_fprintf(F, "fp_mode: %+F\n", attr->fp_mode);
@@ -274,12 +269,20 @@ static void init_sparc_fp_conv_attributes(ir_node *res, ir_mode *src_mode,
        attr->dest_mode = dest_mode;
 }
 
-static void init_sparc_switch_jmp_attributes(ir_node *res, long default_pn,
-                                             ir_entity *jump_table)
+static void init_sparc_switch_jmp_attributes(ir_node *node,
+                                             const ir_switch_table *table,
+                                             ir_entity *table_entity)
 {
-       sparc_switch_jmp_attr_t *attr = get_sparc_switch_jmp_attr(res);
-       attr->default_proj_num = default_pn;
-       attr->jump_table       = jump_table;
+       unsigned n_outs = arch_get_irn_n_outs(node);
+       unsigned o;
+
+       sparc_switch_jmp_attr_t *attr = get_sparc_switch_jmp_attr(node);
+       attr->table        = table;
+       attr->table_entity = table_entity;
+
+       for (o = 0; o < n_outs; ++o) {
+               arch_set_irn_register_req_out(node, o, arch_no_register_req);
+       }
 }
 
 /**
@@ -339,17 +342,6 @@ static int cmp_attr_sparc_jmp_cond(const ir_node *a, const ir_node *b)
            || attr_a->is_unsigned != attr_b->is_unsigned;
 }
 
-static int cmp_attr_sparc_switch_jmp(const ir_node *a, const ir_node *b)
-{
-       const sparc_switch_jmp_attr_t *attr_a = get_sparc_switch_jmp_attr_const(a);
-       const sparc_switch_jmp_attr_t *attr_b = get_sparc_switch_jmp_attr_const(b);
-
-       if (cmp_attr_sparc(a, b))
-               return 1;
-
-       return attr_a->default_proj_num != attr_b->default_proj_num;
-}
-
 static int cmp_attr_sparc_fp(const ir_node *a, const ir_node *b)
 {
        const sparc_fp_attr_t *attr_a = get_sparc_fp_attr_const(a);
index 1f553fc..e249d7c 100644 (file)
@@ -92,9 +92,9 @@ struct sparc_jmp_cond_attr_t {
  */
 typedef struct sparc_switch_jmp_attr_t sparc_switch_jmp_attr_t;
 struct sparc_switch_jmp_attr_t {
-       sparc_attr_t  base;    /**< generic attribute */
-       long          default_proj_num;
-       ir_entity    *jump_table;
+       sparc_attr_t           base;
+       const ir_switch_table *table;
+       ir_entity             *table_entity;
 };
 
 #endif
index 61ac07c..13e0d38 100644 (file)
@@ -131,7 +131,7 @@ $default_copy_attr = "sparc_copy_attr";
        sparc_load_store_attr_t  => "\tinit_sparc_attributes(res, irn_flags_, in_reqs, exec_units, n_res);",
        sparc_jmp_cond_attr_t    => "\tinit_sparc_attributes(res, irn_flags_, in_reqs, exec_units, n_res);",
        sparc_switch_jmp_attr_t  => "\tinit_sparc_attributes(res, irn_flags_, in_reqs, exec_units, n_res);\n".
-                                   "\tinit_sparc_switch_jmp_attributes(res, default_pn, jump_table);\n",
+                                   "\tinit_sparc_switch_jmp_attributes(res, table, jump_table);\n",
        sparc_fp_attr_t          => "\tinit_sparc_attributes(res, irn_flags_, in_reqs, exec_units, n_res);\n".
                                    "\tinit_sparc_fp_attributes(res, fp_mode);\n",
        sparc_fp_conv_attr_t     => "\tinit_sparc_attributes(res, irn_flags_, in_reqs, exec_units, n_res);".
@@ -140,11 +140,11 @@ $default_copy_attr = "sparc_copy_attr";
 
 %compare_attr = (
        sparc_attr_t            => "cmp_attr_sparc",
-       sparc_load_store_attr_t => "cmp_attr_sparc_load_store",
-       sparc_jmp_cond_attr_t   => "cmp_attr_sparc_jmp_cond",
-       sparc_switch_jmp_attr_t => "cmp_attr_sparc_switch_jmp",
        sparc_fp_attr_t         => "cmp_attr_sparc_fp",
        sparc_fp_conv_attr_t    => "cmp_attr_sparc_fp_conv",
+       sparc_jmp_cond_attr_t   => "cmp_attr_sparc_jmp_cond",
+       sparc_load_store_attr_t => "cmp_attr_sparc_load_store",
+       sparc_switch_jmp_attr_t => "cmp_attr_sparc",
 );
 
 %custom_irn_flags = (
@@ -575,9 +575,9 @@ SwitchJmp => {
        state        => "pinned",
        mode         => "mode_T",
        reg_req      => { in => [ "gp" ], out => [ ] },
+       out_arity    => "variable",
        attr_type    => "sparc_switch_jmp_attr_t",
-       attr         => "long default_pn, ir_entity *jump_table",
-       init_attr => "info->out_infos = NULL;", # XXX ugly hack for out requirements
+       attr         => "const ir_switch_table *table, ir_entity *jump_table",
 },
 
 Sll => {
index e13284a..c577224 100644 (file)
@@ -1171,18 +1171,23 @@ static ir_node *gen_Const(ir_node *node)
        }
 }
 
-static ir_node *gen_SwitchJmp(ir_node *node)
-{
-       dbg_info        *dbgi         = get_irn_dbg_info(node);
-       ir_node         *block        = be_transform_node(get_nodes_block(node));
-       ir_node         *selector     = get_Cond_selector(node);
-       ir_node         *new_selector = be_transform_node(selector);
-       long             default_pn   = get_Cond_default_proj(node);
-       ir_entity       *entity;
-       ir_node         *table_address;
-       ir_node         *idx;
-       ir_node         *load;
-       ir_node         *address;
+static ir_node *gen_Switch(ir_node *node)
+{
+       dbg_info              *dbgi         = get_irn_dbg_info(node);
+       ir_node               *block        = get_nodes_block(node);
+       ir_node               *new_block    = be_transform_node(block);
+       ir_graph              *irg          = get_irn_irg(block);
+       ir_node               *selector     = get_Switch_selector(node);
+       ir_node               *new_selector = be_transform_node(selector);
+       const ir_switch_table *table        = get_Switch_table(node);
+       unsigned               n_outs       = get_Switch_n_outs(node);
+       ir_entity             *entity;
+       ir_node               *table_address;
+       ir_node               *idx;
+       ir_node               *load;
+       ir_node               *address;
+
+       table = ir_switch_table_duplicate(irg, table);
 
        /* switch with smaller mode not implemented yet */
        assert(get_mode_size_bits(get_irn_mode(selector)) == 32);
@@ -1192,22 +1197,21 @@ static ir_node *gen_SwitchJmp(ir_node *node)
        add_entity_linkage(entity, IR_LINKAGE_CONSTANT);
 
        /* construct base address */
-       table_address = make_address(dbgi, block, entity, 0);
+       table_address = make_address(dbgi, new_block, entity, 0);
        /* scale index */
-       idx = new_bd_sparc_Sll_imm(dbgi, block, new_selector, NULL, 2);
+       idx = new_bd_sparc_Sll_imm(dbgi, new_block, new_selector, NULL, 2);
        /* load from jumptable */
-       load = new_bd_sparc_Ld_reg(dbgi, block, table_address, idx,
+       load = new_bd_sparc_Ld_reg(dbgi, new_block, table_address, idx,
                                   get_irg_no_mem(current_ir_graph),
                                   mode_gp);
        address = new_r_Proj(load, mode_gp, pn_sparc_Ld_res);
 
-       return new_bd_sparc_SwitchJmp(dbgi, block, address, default_pn, entity);
+       return new_bd_sparc_SwitchJmp(dbgi, new_block, address, n_outs, table, entity);
 }
 
 static ir_node *gen_Cond(ir_node *node)
 {
        ir_node    *selector = get_Cond_selector(node);
-       ir_mode    *mode     = get_irn_mode(selector);
        ir_node    *cmp_left;
        ir_mode    *cmp_mode;
        ir_node    *block;
@@ -1215,11 +1219,6 @@ static ir_node *gen_Cond(ir_node *node)
        ir_relation relation;
        dbg_info   *dbgi;
 
-       /* switch/case jumps */
-       if (mode != mode_b) {
-               return gen_SwitchJmp(node);
-       }
-
        /* note: after lower_mode_b we are guaranteed to have a Cmp input */
        block       = be_transform_node(get_nodes_block(node));
        dbgi        = get_irn_dbg_info(node);
@@ -2426,6 +2425,7 @@ static ir_node *gen_Proj(ir_node *node)
                return gen_Proj_Call(node);
        case iro_Cmp:
                return gen_Proj_Cmp(node);
+       case iro_Switch:
        case iro_Cond:
                return be_duplicate_node(node);
        case iro_Div:
@@ -2498,6 +2498,7 @@ static void sparc_register_transformers(void)
        be_set_transform_function(op_Start,        gen_Start);
        be_set_transform_function(op_Store,        gen_Store);
        be_set_transform_function(op_Sub,          gen_Sub);
+       be_set_transform_function(op_Switch,       gen_Switch);
        be_set_transform_function(op_SymConst,     gen_SymConst);
        be_set_transform_function(op_Unknown,      gen_Unknown);
 
index 3cc3224..d780fae 100644 (file)
@@ -691,17 +691,6 @@ void dump_node_opcode(FILE *F, ir_node *n)
                }
                break;
 
-       case iro_Proj: {
-               ir_node *pred = get_Proj_pred(n);
-
-               if (get_irn_opcode(pred) == iro_Cond
-                       && get_Proj_proj(n) == get_Cond_default_proj(pred)
-                       && get_irn_mode(get_Cond_selector(pred)) != mode_b)
-                       fprintf(F, "defProj");
-               else
-                       goto default_case;
-       } break;
-
        case iro_Load:
                if (get_Load_unaligned(n) == align_non_aligned)
                        fprintf(F, "ua");
@@ -739,7 +728,6 @@ void dump_node_opcode(FILE *F, ir_node *n)
                break;
 
        default:
-default_case:
                fprintf(F, "%s", get_irn_opname(n));
        }
 }
index a4b4085..ec86216 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "irdump_t.h"
 #include "irgraph_t.h"
+#include "irnode_t.h"
 
 #include "irprog_t.h"
 #include "entity_t.h"
@@ -101,8 +102,29 @@ void dump_irnode_to_file(FILE *F, ir_node *n)
 
        fprintf(F, "  Private Attributes:\n");
 
-       if (is_Proj(n))
-               fprintf(F, "  proj nr: %ld\n", get_Proj_proj(n));
+       if (is_Proj(n)) {
+               ir_node *pred = get_Proj_pred(n);
+               long     pn   = get_Proj_proj(n);
+               fprintf(F, "  proj nr: %ld\n", pn);
+               if (is_Switch(pred)) {
+                       const ir_switch_table *table = get_Switch_table(pred);
+                       size_t n_entries = ir_switch_table_get_n_entries(table);
+                       size_t i;
+                       for (i = 0; i < n_entries; ++i) {
+                               const ir_switch_table_entry *entry
+                                       = ir_switch_table_get_entry_const(table, i);
+                               if (entry->pn == pn && entry->min != NULL && entry->max != NULL) {
+                                       ir_tarval *min = entry->min;
+                                       ir_tarval *max = entry->max;
+                                       if (min != max) {
+                                               ir_fprintf(F, "  switch case %+F .. %+F\n", min, max);
+                                       } else {
+                                               ir_fprintf(F, "  switch case %+F\n", min);
+                                       }
+                               }
+                       }
+               }
+       }
 
        if (is_fragile_op(n)) {
                fprintf(F, "  pinned state: %s\n", get_op_pin_state_name(get_irn_pinned(n)));
@@ -157,7 +179,6 @@ void dump_irnode_to_file(FILE *F, ir_node *n)
                        ir_fprintf(F, "    param %d type: %+F\n", i, get_method_param_type(tp, i));
        } break;
        case iro_Cond: {
-               fprintf(F, "  default ProjNr: %ld\n", get_Cond_default_proj(n));
                if (get_Cond_jmp_pred(n) != COND_JMP_PRED_NONE) {
                        fprintf(F, "  jump prediction: %s\n",
                                get_cond_jmp_predicate_name(get_Cond_jmp_pred(n)));
index b36d7c2..a9783c1 100644 (file)
@@ -1709,6 +1709,58 @@ dbg_info *(get_irn_dbg_info)(const ir_node *n)
        return get_irn_dbg_info_(n);
 }
 
+ir_switch_table *ir_new_switch_table(ir_graph *irg, size_t n_entries)
+{
+       struct obstack *obst = get_irg_obstack(irg);
+       ir_switch_table *res = OALLOCFZ(obst, ir_switch_table, entries, n_entries);
+       res->n_entries = n_entries;
+       return res;
+}
+
+void ir_switch_table_set(ir_switch_table *table, size_t n,
+                         ir_tarval *min, ir_tarval *max, long pn)
+{
+       ir_switch_table_entry *entry = ir_switch_table_get_entry(table, n);
+       entry->min = min;
+       entry->max = max;
+       entry->pn  = pn;
+}
+
+size_t (ir_switch_table_get_n_entries)(const ir_switch_table *table)
+{
+       return ir_switch_table_get_n_entries_(table);
+}
+
+ir_tarval *ir_switch_table_get_max(const ir_switch_table *table, size_t e)
+{
+       return ir_switch_table_get_entry_const(table, e)->max;
+}
+
+ir_tarval *ir_switch_table_get_min(const ir_switch_table *table, size_t e)
+{
+       return ir_switch_table_get_entry_const(table, e)->min;
+}
+
+long ir_switch_table_get_pn(const ir_switch_table *table, size_t e)
+{
+       return ir_switch_table_get_entry_const(table, e)->pn;
+}
+
+ir_switch_table *ir_switch_table_duplicate(ir_graph *irg,
+                                           const ir_switch_table *table)
+{
+       size_t n_entries = ir_switch_table_get_n_entries(table);
+       size_t e;
+       ir_switch_table *res = ir_new_switch_table(irg, n_entries);
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               ir_switch_table_entry *new_entry = ir_switch_table_get_entry(res, e);
+               *new_entry = *entry;
+       }
+       return res;
+}
+
 /*
  * Calculate a hash value of a node.
  */
index 7064403..aa2239e 100644 (file)
@@ -604,6 +604,25 @@ static inline int is_arg_Proj_(const ir_node *node)
        return pn_Start_T_args == get_Proj_proj(node) && is_Start(get_Proj_pred(node));
 }
 
+static inline size_t ir_switch_table_get_n_entries_(const ir_switch_table *table)
+{
+       return table->n_entries;
+}
+
+static inline ir_switch_table_entry *ir_switch_table_get_entry(
+               ir_switch_table *table, size_t entry)
+{
+       assert(entry < table->n_entries);
+       return &table->entries[entry];
+}
+
+static inline const ir_switch_table_entry *ir_switch_table_get_entry_const(
+               const ir_switch_table *table, size_t entry)
+{
+       assert(entry < table->n_entries);
+       return &table->entries[entry];
+}
+
 /** initialize ir_node module */
 void init_irnode(void);
 
@@ -684,5 +703,6 @@ void init_irnode(void);
 #define get_Phi_next(node)                    get_Phi_next_(node)
 
 #define is_arg_Proj(node)                     is_arg_Proj_(node)
+#define ir_switch_table_get_n_entries(table)  ir_switch_table_get_n_entries_(table)
 
 #endif
index e584831..c6cc82c 100644 (file)
@@ -117,6 +117,14 @@ static void ASM_copy_attr(ir_graph *irg, const ir_node *old_node,
        new_node->attr.assem.clobbers = DUP_ARR_D(ident*, irg->obst, old_node->attr.assem.clobbers);
 }
 
+static void switch_copy_attr(ir_graph *irg, const ir_node *old_node,
+                             ir_node *new_node)
+{
+       const ir_switch_table *table = get_Switch_table(old_node);
+       new_node->attr.switcha.table = ir_switch_table_duplicate(irg, table);
+       new_node->attr.switcha.n_outs = old_node->attr.switcha.n_outs;
+}
+
 /**
  * Sets the default copy_attr operation for an ir_ops
  *
@@ -129,21 +137,13 @@ static void ASM_copy_attr(ir_graph *irg, const ir_node *old_node,
 static ir_op_ops *firm_set_default_copy_attr(unsigned code, ir_op_ops *ops)
 {
        switch (code) {
-       case iro_Call:
-               ops->copy_attr = call_copy_attr;
-               break;
-       case iro_Block:
-               ops->copy_attr = block_copy_attr;
-               break;
-       case iro_Phi:
-               ops->copy_attr = phi_copy_attr;
-               break;
-       case iro_ASM:
-               ops->copy_attr = ASM_copy_attr;
-               break;
+       case iro_Call:   ops->copy_attr = call_copy_attr;   break;
+       case iro_Block:  ops->copy_attr = block_copy_attr;  break;
+       case iro_Phi:    ops->copy_attr = phi_copy_attr;    break;
+       case iro_ASM:    ops->copy_attr = ASM_copy_attr;    break;
+       case iro_Switch: ops->copy_attr = switch_copy_attr; break;
        default:
-               /* not allowed to be NULL */
-               if (! ops->copy_attr)
+               if (ops->copy_attr == NULL)
                        ops->copy_attr = default_copy_attr;
        }
        return ops;
index a2300fc..94cfe01 100644 (file)
@@ -3468,7 +3468,6 @@ make_tuple:
  */
 static ir_node *transform_node_Cond(ir_node *n)
 {
-
        ir_node   *a   = get_Cond_selector(n);
        ir_graph  *irg = get_irn_irg(n);
        ir_tarval *ta;
@@ -3478,10 +3477,6 @@ static ir_node *transform_node_Cond(ir_node *n)
        if (get_irg_pinned(irg) == op_pin_state_floats)
                return n;
 
-       /* we do not handle switches here */
-       if (get_irn_mode(a) != mode_b)
-               return n;
-
        ta = value_of(a);
        if (ta == tarval_bad && is_Cmp(a)) {
                /* try again with a direct call to compute_cmp, as we don't care
@@ -3509,6 +3504,48 @@ static ir_node *transform_node_Cond(ir_node *n)
        return n;
 }
 
+static ir_node *transform_node_Switch(ir_node *n)
+{
+       ir_node   *op  = get_Switch_selector(n);
+       ir_tarval *val = value_of(op);
+       if (val != tarval_bad) {
+               dbg_info              *dbgi      = get_irn_dbg_info(n);
+               ir_graph              *irg       = get_irn_irg(n);
+               unsigned               n_outs    = get_Switch_n_outs(n);
+               ir_node               *block     = get_nodes_block(n);
+               ir_node               *bad       = new_r_Bad(irg, mode_X);
+               ir_node              **in        = XMALLOCN(ir_node*, n_outs);
+               const ir_switch_table *table     = get_Switch_table(n);
+               size_t                 n_entries = ir_switch_table_get_n_entries(table);
+               long                   jmp_pn    = 0;
+               size_t                 i;
+               unsigned               o;
+               for (i = 0; i < n_entries; ++i) {
+                       const ir_switch_table_entry *entry
+                               = ir_switch_table_get_entry_const(table, i);
+                       ir_tarval *min = entry->min;
+                       ir_tarval *max = entry->max;
+                       if (entry->pn == 0)
+                               continue;
+                       if ((min == max && min == val)
+                           || (tarval_cmp(val, min) != ir_relation_less
+                               && tarval_cmp(val, max) != ir_relation_greater)) {
+                           jmp_pn = entry->pn;
+                           break;
+                       }
+               }
+               for (o = 0; o < n_outs; ++o) {
+                       if (o == (unsigned)jmp_pn) {
+                               in[o] = new_rd_Jmp(dbgi, block);
+                       } else {
+                               in[o] = bad;
+                       }
+               }
+               return new_r_Tuple(block, (int)n_outs, in);
+       }
+       return n;
+}
+
 /**
  * normalisation: (x & c1) >> c2   to   (x >> c2) & (c1 >> c2)
  *  (we can use:
@@ -4140,87 +4177,6 @@ static ir_node *transform_node_Proj_Mod(ir_node *proj)
        return proj;
 }
 
-/**
- * Optimizes jump tables (CondIs or CondIu) by removing all impossible cases.
- */
-static ir_node *transform_node_Proj_Cond(ir_node *proj)
-{
-       ir_node *n = get_Proj_pred(proj);
-       ir_node *b = get_Cond_selector(n);
-
-       if (mode_is_int(get_irn_mode(b))) {
-               ir_tarval *tb = value_of(b);
-
-               if (tb != tarval_bad) {
-                       /* we have a constant switch */
-                       long num = get_Proj_proj(proj);
-
-                       if (num != get_Cond_default_proj(n)) { /* we cannot optimize default Proj's yet */
-                               if (get_tarval_long(tb) == num) {
-                                       /* Do NOT create a jump here, or we will have 2 control flow ops
-                                        * in a block. This case is optimized away in optimize_cf(). */
-                                       return proj;
-                               } else {
-                                       ir_graph *irg = get_irn_irg(proj);
-                                       /* this case will NEVER be taken, kill it */
-                                       clear_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_CODE);
-                                       return new_r_Bad(irg, mode_X);
-                               }
-                       }
-               } else {
-                       long num = get_Proj_proj(proj);
-                       vrp_attr *b_vrp = vrp_get_info(b);
-                       if (num != get_Cond_default_proj(n) && b_vrp) {
-                               /* Try handling with vrp data. We only remove dead parts. */
-                               ir_tarval *tp = new_tarval_from_long(num, get_irn_mode(b));
-
-                               if (b_vrp->range_type == VRP_RANGE) {
-                                       ir_relation cmp_result = tarval_cmp(b_vrp->range_bottom, tp);
-                                       ir_relation cmp_result2 = tarval_cmp(b_vrp->range_top, tp);
-
-                                       if ((cmp_result & ir_relation_greater) == cmp_result
-                                           && (cmp_result2 & ir_relation_less) == cmp_result2) {
-                                               ir_graph *irg = get_irn_irg(proj);
-                                               clear_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_CODE);
-                                               return new_r_Bad(irg, mode_X);
-                                       }
-                               } else if (b_vrp->range_type == VRP_ANTIRANGE) {
-                                       ir_relation cmp_result = tarval_cmp(b_vrp->range_bottom, tp);
-                                       ir_relation cmp_result2 = tarval_cmp(b_vrp->range_top, tp);
-
-                                       if ((cmp_result & ir_relation_less_equal) == cmp_result
-                                            && (cmp_result2 & ir_relation_greater_equal) == cmp_result2) {
-                                               ir_graph *irg = get_irn_irg(proj);
-                                               clear_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_CODE);
-                                               return new_r_Bad(irg, mode_X);
-                                       }
-                               }
-
-                               if (!(tarval_cmp(
-                                                               tarval_and( b_vrp->bits_set, tp),
-                                                               b_vrp->bits_set
-                                                               ) == ir_relation_equal)) {
-                                       ir_graph *irg = get_irn_irg(proj);
-                                       clear_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_CODE);
-                                       return new_r_Bad(irg, mode_X);
-                               }
-
-                               if (!(tarval_cmp(
-                                                               tarval_and(
-                                                                       tarval_not(tp),
-                                                                       tarval_not(b_vrp->bits_not_set)),
-                                                               tarval_not(b_vrp->bits_not_set))
-                                                                == ir_relation_equal)) {
-                                       ir_graph *irg = get_irn_irg(proj);
-                                       clear_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_CODE);
-                                       return new_r_Bad(irg, mode_X);
-                               }
-                       }
-               }
-       }
-       return proj;
-}
-
 /**
  * return true if the operation returns a value with exactly 1 bit set
  */
@@ -6236,6 +6192,7 @@ static ir_op_ops *firm_set_default_transform_node(ir_opcode code, ir_op_ops *ops
        CASE(Block);
        CASE(Call);
        CASE(Cmp);
+       CASE(Cond);
        CASE(Conv);
        CASE(End);
        CASE(Eor);
@@ -6252,11 +6209,11 @@ static ir_op_ops *firm_set_default_transform_node(ir_opcode code, ir_op_ops *ops
        CASE(Shr);
        CASE(Shrs);
        CASE(Sub);
+       CASE(Switch);
        CASE(Sync);
        CASE_PROJ(Bound);
        CASE_PROJ(CopyB);
        CASE_PROJ(Store);
-       CASE_PROJ_EX(Cond);
        CASE_PROJ_EX(Div);
        CASE_PROJ_EX(Load);
        CASE_PROJ_EX(Mod);
index b5786a5..344defd 100644 (file)
@@ -168,6 +168,18 @@ struct ir_mode {
        const void        *tv_priv;     /**< tarval module will save private data here */
 };
 
+/* note: we use "long" here because that is the type used for Proj-Numbers */
+typedef struct ir_switch_table_entry {
+       ir_tarval *min;
+       ir_tarval *max;
+       long       pn;
+} ir_switch_table_entry;
+
+struct ir_switch_table {
+       size_t                n_entries;
+       ir_switch_table_entry entries[];
+};
+
 /* ir node attributes */
 
 /** first attribute of Bad, Block, Anchor nodes */
@@ -363,6 +375,11 @@ typedef struct proj_attr {
        long  proj;           /**< position of tuple sub-value which is projected */
 } proj_attr;
 
+typedef struct switch_attr {
+       unsigned         n_outs;
+       ir_switch_table *table;
+} switch_attr;
+
 /** Some IR-nodes just have one attribute, these are stored here,
    some have more. Their name is 'irnodename_attr' */
 typedef union ir_attr {
@@ -393,6 +410,7 @@ typedef union ir_attr {
        div_attr       div;           /**< For Div operation */
        mod_attr       mod;           /**< For Mod operation */
        asm_attr       assem;         /**< For ASM operation. */
+       switch_attr    switcha;       /**< For Switch operation. */
 } ir_attr;
 
 /**
index de8869d..36c452c 100644 (file)
@@ -348,20 +348,29 @@ static int verify_node_Proj_Start(const ir_node *p)
 static int verify_node_Proj_Cond(const ir_node *p)
 {
        ir_mode *mode = get_irn_mode(p);
-       ir_node *pred = get_Proj_pred(p);
-       long proj     = get_Proj_proj(p);
+       long     proj = get_Proj_proj(p);
 
        ASSERT_AND_RET_DBG(
-               (
-                       (proj >= 0 && mode == mode_X && get_irn_mode(get_Cond_selector(pred)) == mode_b) ||   /* compare */
-                       (mode == mode_X && mode_is_int(get_irn_mode(get_Cond_selector(pred))))                /* switch */
-               ),
+               mode == mode_X && (proj == pn_Cond_false || proj == pn_Cond_true),
                "wrong Proj from Cond", 0,
                show_proj_failure(p);
        );
        return 1;
 }
 
+static int verify_node_Proj_Switch(const ir_node *p)
+{
+       ir_mode *mode = get_irn_mode(p);
+       long     pn   = get_Proj_proj(p);
+       ir_node *pred = get_Proj_pred(p);
+       ASSERT_AND_RET_DBG(
+               mode == mode_X && (pn >= 0 && pn < (long)get_Switch_n_outs(pred)),
+               "wrong Proj from Switch", 0,
+               show_proj_failure(p);
+       );
+       return 1;
+}
+
 /**
  * verify a Proj(Raise) node
  */
@@ -863,14 +872,42 @@ static int verify_node_Cond(const ir_node *n)
        ir_mode *mymode  = get_irn_mode(n);
        ir_mode *op1mode = get_irn_mode(get_Cond_selector(n));
 
-       ASSERT_AND_RET(
-               /* Cond: BB x b --> X x X */
-               (op1mode == mode_b ||
-               /* Cond: BB x int --> X^n */
-               mode_is_int(op1mode) ),  "Cond node", 0
-               );
+       ASSERT_AND_RET(op1mode == mode_b, "Cond operand not mode_b", 0);
        ASSERT_AND_RET(mymode == mode_T, "Cond mode is not a tuple", 0);
+       return 1;
+}
+
+static int verify_switch_table(const ir_node *n)
+{
+       const ir_switch_table *table     = get_Switch_table(n);
+       size_t                 n_entries = ir_switch_table_get_n_entries(table);
+       unsigned               n_outs    = get_Switch_n_outs(n);
+       size_t                 e;
+
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               if (entry->pn == 0)
+                       continue;
+               ASSERT_AND_RET(entry->min != NULL && entry->max != NULL,
+                              "switch table entry without min+max value", 0);
+               ASSERT_AND_RET(tarval_cmp(entry->min, entry->max) != ir_relation_greater,
+                              "switch table entry without min+max value", 0);
+               ASSERT_AND_RET(entry->pn >= 0 && entry->pn < (long)n_outs,
+                                          "switch table entry with invalid proj number", 0);
+       }
+       return 1;
+}
 
+static int verify_node_Switch(const ir_node *n)
+{
+       ir_mode *mymode  = get_irn_mode(n);
+       ir_mode *op1mode = get_irn_mode(get_Switch_selector(n));
+       if (!verify_switch_table(n))
+               return 0;
+
+       ASSERT_AND_RET(mode_is_int(op1mode), "Switch operand not integer", 0);
+       ASSERT_AND_RET(mymode == mode_T, "Switch mode is not a tuple", 0);
        return 1;
 }
 
@@ -1872,16 +1909,14 @@ static int check_block_cfg(const ir_node *block, check_cfg_env_t *env)
 
                if (is_Cond(branch)) {
                        long pn = get_Proj_proj(branch_proj);
-                       if (get_irn_mode(get_Cond_selector(branch)) == mode_b) {
-                               if (pn == pn_Cond_true)
-                                       ir_nodeset_insert(&env->true_projs, branch);
-                               if (pn == pn_Cond_false)
-                                       ir_nodeset_insert(&env->false_projs, branch);
-                       } else {
-                               long default_pn = get_Cond_default_proj(branch);
-                               if (pn == default_pn)
-                                       ir_nodeset_insert(&env->true_projs, branch);
-                       }
+                       if (pn == pn_Cond_true)
+                               ir_nodeset_insert(&env->true_projs, branch);
+                       if (pn == pn_Cond_false)
+                               ir_nodeset_insert(&env->false_projs, branch);
+               } else if (is_Switch(branch)) {
+                       long pn = get_Proj_proj(branch_proj);
+                       if (pn == pn_Switch_default)
+                               ir_nodeset_insert(&env->true_projs, branch);
                }
        }
 
@@ -1910,21 +1945,23 @@ static int verify_block_branch(const ir_node *block, check_cfg_env_t *env)
 
 static int verify_cond_projs(const ir_node *cond, check_cfg_env_t *env)
 {
-       if (get_irn_mode(get_Cond_selector(cond)) == mode_b) {
-               ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->true_projs, cond),
-                                                  "Cond node lacks true proj", 0,
-                                                  ir_printf("Cond %+F\n", cond);
-               );
-               ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->false_projs, cond),
-                                                  "Cond node lacks false proj", 0,
-                                                  ir_printf("Cond %+F\n", cond);
-               );
-       } else {
-               ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->true_projs, cond),
-                                  "Cond node lacks default Proj", 0,
-                                  ir_printf("Cond %+F\n", cond);
-               );
-       }
+       ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->true_projs, cond),
+                                          "Cond node lacks true proj", 0,
+                                          ir_printf("Cond %+F\n", cond);
+       );
+       ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->false_projs, cond),
+                                          "Cond node lacks false proj", 0,
+                                          ir_printf("Cond %+F\n", cond);
+       );
+       return 1;
+}
+
+static int verify_switch_projs(const ir_node *sw, check_cfg_env_t *env)
+{
+       ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->true_projs, sw),
+                                          "Switch node lacks default Proj", 0,
+                                          ir_printf("Switch %+F\n", sw);
+       );
        return 1;
 }
 
@@ -1935,6 +1972,8 @@ static void assert_branch(ir_node *node, void *data)
                env->res &= verify_block_branch(node, env);
        } else if (is_Cond(node)) {
                env->res &= verify_cond_projs(node, env);
+       } else if (is_Switch(node)) {
+               env->res &= verify_switch_projs(node, env);
        }
 }
 
@@ -2210,47 +2249,48 @@ void firm_set_default_verifier(unsigned code, ir_op_ops *ops)
      break
 
        switch (code) {
-       CASE(Proj);
+       CASE(Add);
+       CASE(Alloc);
+       CASE(And);
        CASE(Block);
-       CASE(Start);
-       CASE(Jmp);
-       CASE(IJmp);
+       CASE(Bound);
+       CASE(Call);
+       CASE(Cast);
+       CASE(Cmp);
        CASE(Cond);
-       CASE(Return);
-       CASE(Raise);
+       CASE(Confirm);
        CASE(Const);
-       CASE(SymConst);
-       CASE(Sel);
+       CASE(Conv);
+       CASE(CopyB);
+       CASE(Div);
+       CASE(Eor);
+       CASE(Free);
+       CASE(IJmp);
        CASE(InstOf);
-       CASE(Call);
-       CASE(Add);
-       CASE(Sub);
+       CASE(Jmp);
+       CASE(Load);
        CASE(Minus);
+       CASE(Mod);
        CASE(Mul);
        CASE(Mulh);
-       CASE(Div);
-       CASE(Mod);
-       CASE(And);
-       CASE(Or);
-       CASE(Eor);
+       CASE(Mux);
        CASE(Not);
-       CASE(Cmp);
+       CASE(Or);
+       CASE(Phi);
+       CASE(Proj);
+       CASE(Raise);
+       CASE(Return);
+       CASE(Rotl);
+       CASE(Sel);
        CASE(Shl);
        CASE(Shr);
        CASE(Shrs);
-       CASE(Rotl);
-       CASE(Conv);
-       CASE(Cast);
-       CASE(Phi);
-       CASE(Load);
+       CASE(Start);
        CASE(Store);
-       CASE(Alloc);
-       CASE(Free);
+       CASE(Sub);
+       CASE(Switch);
+       CASE(SymConst);
        CASE(Sync);
-       CASE(Confirm);
-       CASE(Mux);
-       CASE(CopyB);
-       CASE(Bound);
        default:
                break;
        }
@@ -2262,20 +2302,21 @@ void firm_set_default_verifier(unsigned code, ir_op_ops *ops)
      break
 
        switch (code) {
-       CASE(Start);
-       CASE(Cond);
-       CASE(Raise);
-       CASE(InstOf);
+       CASE(Alloc);
+       CASE(Bound);
        CASE(Call);
+       CASE(Cond);
+       CASE(CopyB);
        CASE(Div);
-       CASE(Mod);
+       CASE(InstOf);
        CASE(Load);
-       CASE(Store);
-       CASE(Alloc);
+       CASE(Mod);
        CASE(Proj);
+       CASE(Raise);
+       CASE(Start);
+       CASE(Store);
+       CASE(Switch);
        CASE(Tuple);
-       CASE(CopyB);
-       CASE(Bound);
        default:
                break;
        }
index c81d373..02bc306 100644 (file)
@@ -1228,6 +1228,18 @@ static ir_node *get_cfop_destination(const ir_node *cfop)
        return get_edge_src_irn(first);
 }
 
+static void lower_Switch(ir_node *node, ir_mode *high_mode)
+{
+       ir_node *selector = get_Switch_selector(node);
+       ir_mode *mode     = get_irn_mode(selector);
+       (void)high_mode;
+       if (mode == env->high_signed || mode == env->high_unsigned) {
+               /* we can't really handle Switch with 64bit offsets */
+               panic("Switch with 64bit jumptable not supported");
+       }
+       lower_node(selector);
+}
+
 /**
  * Translate a Cond.
  */
@@ -1235,7 +1247,6 @@ static void lower_Cond(ir_node *node, ir_mode *high_mode)
 {
        ir_node *left, *right, *block;
        ir_node *sel = get_Cond_selector(node);
-       ir_mode *m = get_irn_mode(sel);
        ir_mode *cmp_mode;
        const lower64_entry_t *lentry, *rentry;
        ir_node  *projT = NULL, *projF = NULL;
@@ -1250,15 +1261,6 @@ static void lower_Cond(ir_node *node, ir_mode *high_mode)
 
        (void) high_mode;
 
-       if (m != mode_b) {
-               if (m == env->high_signed || m == env->high_unsigned) {
-                       /* bad we can't really handle Switch with 64bit offsets */
-                       panic("Cond with 64bit jumptable not supported");
-               }
-               lower_node(sel);
-               return;
-       }
-
        if (!is_Cmp(sel)) {
                lower_node(sel);
                return;
@@ -2957,6 +2959,7 @@ void ir_prepare_dw_lowering(const lwrdw_param_t *new_param)
        ir_register_dw_lower_function(op_Start,   lower_Start);
        ir_register_dw_lower_function(op_Store,   lower_Store);
        ir_register_dw_lower_function(op_Sub,     lower_binop);
+       ir_register_dw_lower_function(op_Switch,  lower_Switch);
        ir_register_dw_lower_function(op_Unknown, lower_Unknown);
 }
 
index d6d852b..800312e 100644 (file)
@@ -51,113 +51,247 @@ typedef struct walk_env_t {
 } walk_env_t;
 
 typedef struct case_data_t {
-       long     value;
-       ir_node *target;
+       const ir_switch_table_entry *entry;
+       ir_node                     *target;
 } case_data_t;
 
-typedef struct cond_env_t {
-       ir_node  *sel;
-       long      switch_min;
-       long      switch_max;
-       ir_node  *default_block;
-       unsigned  num_cases;
-       ir_node **defusers;           /**< the Projs pointing to the default case */
-} cond_env_t;
+typedef struct switch_info_t {
+       ir_node     *switchn;
+       long         switch_min;
+       long         switch_max;
+       ir_node     *default_block;
+       unsigned     num_cases;
+       case_data_t *cases;
+       ir_node    **defusers;    /**< the Projs pointing to the default case */
+} switch_info_t;
 
-static void analyse_switch(cond_env_t *env, ir_node *cond)
+/**
+ * analyze enough to decide if we should lower the switch
+ */
+static bool analyse_switch0(switch_info_t *info, ir_node *switchn)
 {
-       long     default_pn    = get_Cond_default_proj(cond);
-       long     switch_min    = LONG_MAX;
-       long     switch_max    = LONG_MIN;
-       ir_node *default_block = NULL;
-       unsigned num_cases     = 0;
-       int      i;
-       ir_node *proj;
-
-       foreach_out_irn(cond, i, proj) {
-               long pn = get_Proj_proj(proj);
-               if (pn == default_pn) {
-                       ir_node *target = get_irn_out(proj, 0);
-                       assert(default_block == NULL || default_block == target);
-                       default_block = target;
+       const ir_switch_table *table         = get_Switch_table(switchn);
+       size_t                 n_entries     = ir_switch_table_get_n_entries(table);
+       long                   switch_min    = LONG_MAX;
+       long                   switch_max    = LONG_MIN;
+       unsigned               num_cases     = 0;
+       size_t                 e;
+
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               long minval;
+               long maxval;
+               if (entry->pn == 0)
                        continue;
-               }
 
-               if (pn < switch_min)
-                       switch_min = pn;
-               if (pn > switch_max)
-                       switch_max = pn;
+               if (!tarval_is_long(entry->min) || !tarval_is_long(entry->max))
+                       return false;
+               minval = get_tarval_long(entry->min);
+               maxval = get_tarval_long(entry->max);
+               if (minval < switch_min)
+                       switch_min = minval;
+               if (maxval > switch_max)
+                       switch_max = maxval;
                ++num_cases;
        }
-       assert(default_block != NULL);
 
-       env->switch_min    = switch_min;
-       env->switch_max    = switch_max;
-       env->num_cases     = num_cases;
-       env->default_block = default_block;
+       info->switchn    = switchn;
+       info->switch_min = switch_min;
+       info->switch_max = switch_max;
+       info->num_cases  = num_cases;
+       return true;
 }
 
 static int casecmp(const void *a, const void *b)
 {
-       const case_data_t *cda = (const case_data_t*)a;
-       const case_data_t *cdb = (const case_data_t*)b;
+       const case_data_t           *cda = (const case_data_t*)a;
+       const case_data_t           *cdb = (const case_data_t*)b;
+       const ir_switch_table_entry *ea  = cda->entry;
+       const ir_switch_table_entry *eb  = cdb->entry;
+
+       if (ea == eb)
+               return 0;
+
+       if (tarval_cmp(ea->max, eb->min) == ir_relation_less)
+               return -1;
+       /* cases must be non overlapping, so the only remaining case is greater */
+       assert(tarval_cmp(ea->min, eb->max) == ir_relation_greater);
+       return 1;
+}
+
+/**
+ * Analyse the stuff that anayse_switch0() left out
+ */
+static void analyse_switch1(switch_info_t *info)
+{
+       const ir_node         *switchn   = info->switchn;
+       const ir_switch_table *table     = get_Switch_table(switchn);
+       size_t                 n_entries = ir_switch_table_get_n_entries(table);
+       unsigned               n_outs    = get_Switch_n_outs(switchn);
+       ir_node              **targets   = XMALLOCNZ(ir_node*, n_outs);
+       unsigned               num_cases = info->num_cases;
+       case_data_t           *cases     = XMALLOCN(case_data_t, num_cases);
+       unsigned               c         = 0;
+       size_t                 e;
+       int                    i;
+       ir_node               *proj;
+
+       foreach_out_irn(switchn, i, proj) {
+               long     pn     = get_Proj_proj(proj);
+               ir_node *target = get_irn_out(proj, 0);
+
+               assert((unsigned)pn < n_outs);
+               assert(targets[(unsigned)pn] == NULL);
+               targets[(unsigned)pn] = target;
+       }
+
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               if (entry->pn == 0)
+                       continue;
+
+               cases[c].entry  = entry;
+               cases[c].target = targets[entry->pn];
+               ++c;
+       }
+       assert(c == num_cases);
 
        /*
-        * Enforce unsigned sorting. Signed comparison will behave differently for
-        * 32-bit values, depending on sizeof(long). This will make the resulting
-        * array deterministic.
+        * Switch should be transformed into an if cascade.
+        * So first order the cases, so we can do a binary search on them.
         */
-       return ((unsigned long)cda->value > (unsigned long)cdb->value) -
-              ((unsigned long)cda->value < (unsigned long)cdb->value);
+       qsort(cases, num_cases, sizeof(cases[0]), casecmp);
+
+       info->default_block = targets[pn_Switch_default];
+       info->cases         = cases;
+}
+
+static void normalize_table(ir_node *switchn, ir_mode *new_mode,
+                            ir_tarval *delta)
+{
+       ir_switch_table *table     = get_Switch_table(switchn);
+       size_t           n_entries = ir_switch_table_get_n_entries(table);
+       size_t           e;
+       /* adapt switch_table */
+       for (e = 0; e < n_entries; ++e) {
+               ir_switch_table_entry *entry = ir_switch_table_get_entry(table, e);
+               ir_tarval *min = entry->min;
+
+               if (entry->pn == 0)
+                       continue;
+
+               min = tarval_convert_to(min, new_mode);
+               if (delta != NULL)
+                       min = tarval_sub(min, delta, NULL);
+
+               if (entry->min == entry->max) {
+                       entry->min = min;
+                       entry->max = min;
+               } else {
+                       ir_tarval *max = entry->max;
+                       max = tarval_convert_to(max, new_mode);
+                       if (delta != NULL)
+                               max = tarval_sub(max, delta, NULL);
+                       entry->min = min;
+                       entry->max = max;
+               }
+       }
+}
+
+/**
+ * normalize switch to work on an unsigned input with the first case at 0
+ */
+static void normalize_switch(switch_info_t *info)
+{
+       ir_node   *switchn     = info->switchn;
+       ir_graph  *irg         = get_irn_irg(switchn);
+       ir_node   *block       = get_nodes_block(switchn);
+       ir_node   *selector    = get_Switch_selector(switchn);
+       ir_mode   *mode        = get_irn_mode(selector);
+       ir_tarval *delta       = NULL;
+       bool       change_mode = false;
+
+       if (mode_is_signed(mode)) {
+               mode        = find_unsigned_mode(mode);
+               selector    = new_r_Conv(block, selector, mode);
+               change_mode = true;
+       }
+
+       /* normalize so switch_min is at 0 */
+       if (info->switch_min != 0) {
+               dbg_info *dbgi = get_irn_dbg_info(switchn);
+               ir_node  *min_const;
+
+               delta = new_tarval_from_long(info->switch_min, mode);
+
+               min_const = new_r_Const(irg, delta);
+               selector  = new_rd_Sub(dbgi, block, selector, min_const, mode);
+
+               info->switch_min  = 0;
+               info->switch_max -= info->switch_min;
+       }
+
+       if (delta != NULL || change_mode) {
+               set_Switch_selector(switchn, selector);
+               normalize_table(switchn, mode, delta);
+       }
+}
+
+/**
+ * Create an if (selector == caseval) Cond node (and handle the special case
+ * of ranged cases)
+ */
+static ir_node *create_case_cond(const ir_switch_table_entry *entry,
+                                 dbg_info *dbgi, ir_node *block,
+                                 ir_node *selector)
+{
+       ir_graph *irg      = get_irn_irg(block);
+       ir_node  *minconst = new_r_Const(irg, entry->min);
+       ir_node  *cmp;
+
+       if (entry->min == entry->max) {
+               cmp = new_rd_Cmp(dbgi, block, selector, minconst, ir_relation_equal);
+       } else {
+               ir_tarval *adjusted_max = tarval_sub(entry->max, entry->min, NULL);
+               ir_node   *sub          = new_rd_Sub(dbgi, block, selector, minconst,
+                                                    get_tarval_mode(adjusted_max));
+               ir_node   *maxconst     = new_r_Const(irg, adjusted_max);
+               cmp = new_rd_Cmp(dbgi, block, sub, maxconst, ir_relation_less_equal);
+       }
+
+       return new_rd_Cond(dbgi, block, cmp);
 }
 
 /**
  * Creates an if cascade realizing binary search.
  */
-static void create_if_cascade(cond_env_t *env, dbg_info *dbgi, ir_node *block,
+static void create_if_cascade(switch_info_t *info, ir_node *block,
                               case_data_t *curcases, unsigned numcases)
 {
-       ir_graph *irg = get_irn_irg(block);
-    ir_mode  *cmp_mode;
-    ir_node  *cmp_sel;
-    ir_node  *sel_block;
-
-    /* Get the mode and sel node for the comparison. */
-    cmp_mode  = get_irn_mode(env->sel);
-    cmp_sel   = env->sel;
-    sel_block = get_nodes_block(cmp_sel);
-
-    /*
-     * Make sure that an unsigned comparison is used, by converting the sel
-     * node to an unsigned mode and using that mode for the constants, too.
-     * This is important, because the qsort applied to the case labels uses
-     * an unsigned comparison and both comparison methods have to match.
-     */
-    if (mode_is_signed(cmp_mode)) {
-        cmp_mode = find_unsigned_mode(cmp_mode);
-        cmp_sel  = new_r_Conv(sel_block, cmp_sel, cmp_mode);
-    }
+       ir_graph      *irg      = get_irn_irg(block);
+       const ir_node *switchn  = info->switchn;
+       dbg_info      *dbgi     = get_irn_dbg_info(switchn);
+       ir_node       *selector = get_Switch_selector(switchn);
 
        if (numcases == 0) {
                /* zero cases: "goto default;" */
-               ARR_APP1(ir_node*, env->defusers, new_r_Jmp(block));
+               ARR_APP1(ir_node*, info->defusers, new_r_Jmp(block));
        } else if (numcases == 1) {
-               /* only one case: "if (sel == val) goto target else goto default;" */
-               ir_node *val       = new_r_Const_long(irg, cmp_mode, curcases[0].value);
-               ir_node *cmp       = new_rd_Cmp(dbgi, block, cmp_sel, val,
-                                               ir_relation_equal);
-               ir_node *cond      = new_rd_Cond(dbgi, block, cmp);
+               /*only one case: "if (sel == val) goto target else goto default;"*/
+               const ir_switch_table_entry *entry = curcases[0].entry;
+               ir_node *cond      = create_case_cond(entry, dbgi, block, selector);
                ir_node *trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
                ir_node *falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
 
                set_Block_cfgpred(curcases[0].target, 0, trueproj);
-               ARR_APP1(ir_node*, env->defusers, falseproj);
+               ARR_APP1(ir_node*, info->defusers, falseproj);
        } else if (numcases == 2) {
                /* only two cases: "if (sel == val[0]) goto target[0];" */
-               ir_node *val       = new_r_Const_long(irg, cmp_mode, curcases[0].value);
-               ir_node *cmp       = new_rd_Cmp(dbgi, block, cmp_sel, val,
-                                               ir_relation_equal);
-               ir_node *cond      = new_rd_Cond(dbgi, block, cmp);
+               const ir_switch_table_entry *entry0 = curcases[0].entry;
+               const ir_switch_table_entry *entry1 = curcases[1].entry;
+               ir_node *cond      = create_case_cond(entry0, dbgi, block, selector);
                ir_node *trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
                ir_node *falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
                ir_node *in[1];
@@ -169,19 +303,17 @@ static void create_if_cascade(cond_env_t *env, dbg_info *dbgi, ir_node *block,
                neblock = new_r_Block(irg, 1, in);
 
                /* second part: "else if (sel == val[1]) goto target[1] else goto default;" */
-               val       = new_r_Const_long(irg, cmp_mode, curcases[1].value);
-               cmp       = new_rd_Cmp(dbgi, neblock, cmp_sel, val, ir_relation_equal);
-               cond      = new_rd_Cond(dbgi, neblock, cmp);
+               cond      = create_case_cond(entry1, dbgi, neblock, selector);
                trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
                falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
                set_Block_cfgpred(curcases[1].target, 0, trueproj);
-               ARR_APP1(ir_node*, env->defusers, falseproj);
+               ARR_APP1(ir_node*, info->defusers, falseproj);
        } else {
                /* recursive case: split cases in the middle */
-               int midcase = numcases / 2;
-               ir_node *val  = new_r_Const_long(irg, cmp_mode,
-                                                curcases[midcase].value);
-               ir_node *cmp  = new_rd_Cmp(dbgi, block, cmp_sel, val, ir_relation_less);
+               unsigned midcase = numcases / 2;
+               const ir_switch_table_entry *entry = curcases[midcase].entry;
+               ir_node *val = new_r_Const(irg, entry->min);
+               ir_node *cmp = new_rd_Cmp(dbgi, block, selector, val, ir_relation_less);
                ir_node *cond = new_rd_Cond(dbgi, block, cmp);
                ir_node *in[1];
                ir_node *ltblock;
@@ -193,82 +325,64 @@ static void create_if_cascade(cond_env_t *env, dbg_info *dbgi, ir_node *block,
                in[0]   = new_r_Proj(cond, mode_X, pn_Cond_false);
                geblock = new_r_Block(irg, 1, in);
 
-               create_if_cascade(env, dbgi, ltblock, curcases, midcase);
-               create_if_cascade(env, dbgi, geblock, curcases + midcase,
-                                 numcases - midcase);
+               create_if_cascade(info, ltblock, curcases, midcase);
+               create_if_cascade(info, geblock, curcases + midcase, numcases - midcase);
        }
 }
 
-static void create_out_of_bounds_check(cond_env_t *env, ir_node *cond)
+static void create_out_of_bounds_check(switch_info_t *info)
 {
-       ir_graph      *irg           = get_irn_irg(cond);
-       dbg_info      *dbgi          = get_irn_dbg_info(cond);
-       ir_node       *sel           = get_Cond_selector(cond);
-       ir_node       *block         = get_nodes_block(cond);
-       ir_mode       *cmp_mode      = get_irn_mode(sel);
-       ir_node      **default_preds = NEW_ARR_F(ir_node*, 0);
-       long           default_pn    = get_Cond_default_proj(cond);
-       long           delta         = 0;
-       ir_node       *max_const;
-       ir_node       *proj_true;
-       ir_node       *proj_false;
-       ir_node       *cmp;
-       ir_node       *oob_cond;
-       ir_node       *in[1];
-       ir_node       *new_block;
-       size_t         n_default_preds;
-       int            i;
-       ir_node       *proj;
-
-       if (mode_is_signed(cmp_mode)) {
-               cmp_mode = find_unsigned_mode(cmp_mode);
-               sel      = new_r_Conv(block, sel, cmp_mode);
-       }
-
-       /* normalize so switch_min is at 0 */
-       if (env->switch_min != 0) {
-               ir_node *min_const  = new_r_Const_long(irg, cmp_mode, env->switch_min);
-               sel = new_rd_Sub(dbgi, block, sel, min_const, cmp_mode);
-
-               delta            = env->switch_min;
-               env->switch_min  = 0;
-               env->switch_max -= delta;
-               set_Cond_selector(cond, sel);
-       }
+       ir_node    *switchn       = info->switchn;
+       ir_graph   *irg           = get_irn_irg(switchn);
+       dbg_info   *dbgi          = get_irn_dbg_info(switchn);
+       ir_node    *selector      = get_Switch_selector(switchn);
+       ir_node    *block         = get_nodes_block(switchn);
+       ir_mode    *cmp_mode      = get_irn_mode(selector);
+       ir_node   **default_preds = NEW_ARR_F(ir_node*, 0);
+       ir_node    *default_block = NULL;
+       ir_node    *max_const;
+       ir_node    *proj_true;
+       ir_node    *proj_false;
+       ir_node    *cmp;
+       ir_node    *oob_cond;
+       ir_node    *in[1];
+       ir_node    *new_block;
+       int         i;
+       ir_node    *proj;
+       size_t      n_default_preds;
+
+       assert(info->switch_min == 0);
 
        /* check for out-of-bounds */
-       max_const  = new_r_Const_long(irg, cmp_mode, env->switch_max);
-       cmp        = new_rd_Cmp(dbgi, block, sel, max_const, ir_relation_less_equal);
+       max_const  = new_r_Const_long(irg, cmp_mode, info->switch_max);
+       cmp        = new_rd_Cmp(dbgi, block, selector, max_const, ir_relation_less_equal);
        oob_cond   = new_rd_Cond(dbgi, block, cmp);
        proj_true  = new_r_Proj(oob_cond, mode_X, pn_Cond_true);
        proj_false = new_r_Proj(oob_cond, mode_X, pn_Cond_false);
 
        ARR_APP1(ir_node*, default_preds, proj_false);
 
-       /* create new block containing the cond */
+       /* create new block containing the switch */
        in[0] = proj_true;
        new_block = new_r_Block(irg, 1, in);
-       set_nodes_block(cond, new_block);
-
-       /* adapt projs */
-       foreach_out_irn(cond, i, proj) {
-               long pn     = get_Proj_proj(proj);
-               long new_pn = pn - delta;
-               if (pn == default_pn) {
-                       set_Cond_default_proj(cond, new_pn);
+       set_nodes_block(switchn, new_block);
+
+       /* adjust projs */
+       foreach_out_irn(switchn, i, proj) {
+               long pn = get_Proj_proj(proj);
+               if (pn == pn_Switch_default) {
+                       assert(default_block == NULL);
+                       default_block = get_irn_out(proj, 0);
                        ARR_APP1(ir_node*, default_preds, proj);
                }
-
-               set_Proj_proj(proj, new_pn);
                set_nodes_block(proj, new_block);
        }
 
        /* adapt default block */
        n_default_preds = ARR_LEN(default_preds);
        if (n_default_preds > 1) {
-               size_t p;
-
                /* create new intermediate blocks so we don't have critical edges */
+               size_t p;
                for (p = 0; p < n_default_preds; ++p) {
                        ir_node *pred = default_preds[p];
                        ir_node *split_block;
@@ -280,33 +394,26 @@ static void create_out_of_bounds_check(cond_env_t *env, ir_node *cond)
                        default_preds[p] = new_r_Jmp(split_block);
                }
        }
-       set_irn_in(env->default_block, n_default_preds, default_preds);
+       set_irn_in(default_block, n_default_preds, default_preds);
 
        DEL_ARR_F(default_preds);
+
+       clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_DOMINANCE
+                          | IR_GRAPH_STATE_VALID_EXTENDED_BLOCKS);
 }
 
 /**
- * Block-Walker: searches for Cond nodes with a non-boolean mode
+ * Block-Walker: searches for Switch nodes
  */
-static void find_cond_nodes(ir_node *block, void *ctx)
+static void find_switch_nodes(ir_node *block, void *ctx)
 {
-       walk_env_t  *env = (walk_env_t *)ctx;
-       ir_node     *projx;
-       ir_node     *cond;
-       ir_node     *sel;
-       ir_mode     *sel_mode;
-       long         default_pn;
-       int          i;
-       unsigned     j = 0;
-       unsigned     numcases;
-       ir_node     *proj;
-       case_data_t *cases;
-       ir_node     *condblock;
-       ir_node     *defblock = NULL;
-       dbg_info    *dbgi;
-       cond_env_t   cond_env;
+       walk_env_t   *env = (walk_env_t *)ctx;
+       ir_node      *projx;
+       ir_node      *switchn;
+       switch_info_t info;
        unsigned long spare;
-       bool         lower_switch = false;
+       bool          lower_switch = false;
+       bool          could_analyze;
 
        /* because we split critical blocks only blocks with 1 predecessors may
         * contain Proj->Cond nodes */
@@ -318,90 +425,58 @@ static void find_cond_nodes(ir_node *block, void *ctx)
                return;
        assert(get_irn_mode(projx) == mode_X);
 
-       cond = get_Proj_pred(projx);
-       if (!is_Cond(cond))
+       switchn = get_Proj_pred(projx);
+       if (!is_Switch(switchn))
                return;
 
-       sel      = get_Cond_selector(cond);
-       sel_mode = get_irn_mode(sel);
-
-       if (sel_mode == mode_b)
+       if (ir_nodeset_contains(&env->processed, switchn))
                return;
+       ir_nodeset_insert(&env->processed, switchn);
 
-       if (ir_nodeset_contains(&env->processed, cond))
+       could_analyze = analyse_switch0(&info, switchn);
+       /* the code can't handle values which are not representable in the host */
+       if (!could_analyze) {
+               ir_fprintf(stderr, "libfirm warning: Couldn't analyse %+F (this could go wrong in the backend)\n", switchn);
                return;
-       ir_nodeset_insert(&env->processed, cond);
-
-       /* the algorithms here don't work reliable for modes bigger than 32
-        * since we operate with long numbers */
-       assert(get_mode_size_bits(sel_mode) <= 32);
-
-       analyse_switch(&cond_env, cond);
+       }
 
        /*
         * Here we have: num_cases and [switch_min, switch_max] interval.
         * We do an if-cascade if there are too many spare numbers.
         */
-       spare = (unsigned long) cond_env.switch_max
-               - (unsigned long) cond_env.switch_min
-               - (unsigned long) cond_env.num_cases + 1;
+       spare = (unsigned long) info.switch_max
+               - (unsigned long) info.switch_min
+               - (unsigned long) info.num_cases + 1;
        lower_switch |= spare >= env->spare_size;
-       lower_switch |= cond_env.num_cases <= env->small_switch;
+       lower_switch |= info.num_cases <= env->small_switch;
 
        if (!lower_switch) {
                /* we won't decompose the switch. But we might have to add
                 * out-of-bounds checking */
                if (!env->allow_out_of_bounds) {
-                       create_out_of_bounds_check(&cond_env, cond);
-                       env->changed = true;
+                       normalize_switch(&info);
+                       create_out_of_bounds_check(&info);
                }
                return;
        }
 
-       /*
-        * Switch should be transformed into an if cascade.
-        * So first order the cases, so we can do a binary search on them.
-        */
-       env->changed = true;
-
-       numcases = get_irn_n_outs(cond) - 1; /* does not contain default case */
-       cases    = XMALLOCN(case_data_t, numcases);
-
-       default_pn        = get_Cond_default_proj(cond);
-       cond_env.sel      = sel;
-       cond_env.defusers = NEW_ARR_F(ir_node*, 0);
-
-       foreach_out_irn(cond, i, proj) {
-               long pn = get_Proj_proj(proj);
-               ir_node *target = get_irn_out(proj, 0);
-               assert(get_Block_n_cfgpreds(target) == 1);
-
-               if (pn == default_pn) {
-                       defblock = target;
-                       continue;
-               }
-
-               cases[j].value  = pn;
-               cases[j].target = target;
-               j++;
-       }
-       assert(j == numcases);
-
-       if (defblock == NULL)
-               panic("Switch %+F has no default proj", cond);
-
-       qsort(cases, numcases, sizeof(cases[0]), casecmp);
+       normalize_switch(&info);
+       analyse_switch1(&info);
 
        /* Now create the if cascade */
-       condblock = get_nodes_block(cond);
-       dbgi      = get_irn_dbg_info(cond);
-       create_if_cascade(&cond_env, dbgi, condblock, cases, numcases);
+       env->changed   = true;
+       info.defusers = NEW_ARR_F(ir_node*, 0);
+       block          = get_nodes_block(switchn);
+       create_if_cascade(&info, block, info.cases, info.num_cases);
 
        /* Connect new default case users */
-       set_irn_in(defblock, ARR_LEN(cond_env.defusers), cond_env.defusers);
+       set_irn_in(info.default_block, ARR_LEN(info.defusers), info.defusers);
 
-       xfree(cases);
-       DEL_ARR_F(cond_env.defusers);
+       DEL_ARR_F(info.defusers);
+       xfree(info.cases);
+       clear_irg_state(get_irn_irg(block), IR_GRAPH_STATE_NO_CRITICAL_EDGES
+                                         | IR_GRAPH_STATE_CONSISTENT_DOMINANCE
+                                         | IR_GRAPH_STATE_VALID_EXTENDED_BLOCKS);
 }
 
 void lower_switch(ir_graph *irg, unsigned small_switch, unsigned spare_size,
@@ -417,12 +492,6 @@ void lower_switch(ir_graph *irg, unsigned small_switch, unsigned spare_size,
        remove_critical_cf_edges(irg);
        assure_irg_outs(irg);
 
-       irg_block_walk_graph(irg, find_cond_nodes, NULL, &env);
+       irg_block_walk_graph(irg, find_switch_nodes, NULL, &env);
        ir_nodeset_destroy(&env.processed);
-
-       if (env.changed) {
-               /* control flow changed */
-               clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_DOMINANCE
-                                  | IR_GRAPH_STATE_VALID_EXTENDED_BLOCKS);
-       }
 }
index 30910cb..12df7ed 100644 (file)
@@ -109,8 +109,7 @@ static void clear_link_and_mark_blocks_removable(ir_node *node, void *ctx)
  */
 static void collect_nodes(ir_node *n, void *ctx)
 {
-       ir_node ***switch_conds = (ir_node***)ctx;
-
+       (void) ctx;
        if (is_Phi(n)) {
                /* Collect Phi nodes to compact ins along with block's ins. */
                ir_node *block = get_nodes_block(n);
@@ -134,9 +133,6 @@ static void collect_nodes(ir_node *n, void *ctx)
                        ir_node *pred = get_Proj_pred(n);
                        set_irn_link(n, get_irn_link(pred));
                        set_irn_link(pred, n);
-               } else if (is_Cond(n) && is_switch_Cond(n)) {
-                       /* found a switch-Cond, collect */
-                       ARR_APP1(ir_node*, *switch_conds, n);
                }
        }
 }
@@ -513,77 +509,6 @@ static void optimize_blocks(ir_node *b, void *ctx)
        xfree(in);
 }
 
-/**
- * Optimize table-switch Conds.
- *
- * @param cond the switch-Cond
- * @return true if the switch-Cond was optimized
- */
-static bool handle_switch_cond(ir_node *cond)
-{
-       ir_node *sel   = get_Cond_selector(cond);
-       ir_node *proj1 = (ir_node*)get_irn_link(cond);
-       ir_node *proj2 = (ir_node*)get_irn_link(proj1);
-       ir_node *blk   = get_nodes_block(cond);
-
-       /* exactly 1 Proj on the Cond node: must be the defaultProj */
-       if (proj2 == NULL) {
-               ir_node *jmp = new_r_Jmp(blk);
-               assert(get_Cond_default_proj(cond) == get_Proj_proj(proj1));
-               /* convert it into a Jmp */
-               exchange(proj1, jmp);
-               return true;
-       }
-
-       /* handle Cond nodes with constant argument. In this case the localopt rules
-        * should have killed all obviously impossible cases.
-        * So the only case left to handle here is 1 defaultProj + 1 case
-        * (this one case should be the one taken) */
-       if (get_irn_link(proj2) == NULL) {
-               ir_tarval *tv = value_of(sel);
-
-               if (tv != tarval_bad) {
-                       /* we have a constant switch */
-                       long      num     = get_tarval_long(tv);
-                       long      def_num = get_Cond_default_proj(cond);
-                       ir_graph *irg     = get_irn_irg(cond);
-                       ir_node  *bad     = new_r_Bad(irg, mode_X);
-
-                       if (def_num == get_Proj_proj(proj1)) {
-                               /* first one is the defProj */
-                               if (num == get_Proj_proj(proj2)) {
-                                       ir_node *jmp = new_r_Jmp(blk);
-                                       exchange(proj2, jmp);
-                                       exchange(proj1, bad);
-                                       return true;
-                               }
-                       } else if (def_num == get_Proj_proj(proj2)) {
-                               /* second one is the defProj */
-                               if (num == get_Proj_proj(proj1)) {
-                                       ir_node *jmp = new_r_Jmp(blk);
-                                       exchange(proj1, jmp);
-                                       exchange(proj2, bad);
-                                       return true;
-                               }
-                       } else {
-                               /* neither: strange, Cond was not optimized so far */
-                               if (num == get_Proj_proj(proj1)) {
-                                       ir_node *jmp = new_r_Jmp(blk);
-                                       exchange(proj1, jmp);
-                                       exchange(proj2, bad);
-                                       return true;
-                               } else if (num == get_Proj_proj(proj2)) {
-                                       ir_node *jmp = new_r_Jmp(blk);
-                                       exchange(proj2, jmp);
-                                       exchange(proj1, bad);
-                                       return true;
-                               }
-                       }
-               }
-       }
-       return false;
-}
-
 /**
  * Optimize boolean Conds, where true and false jump to the same block into a Jmp
  * Block must contain no Phi nodes.
@@ -900,8 +825,6 @@ static ir_graph_state_t do_cfopt(ir_graph *irg)
 
        /* The switch Cond optimization might expose unreachable code, so we loop */
        for (;;) {
-               int length;
-               ir_node **switch_conds = NULL;
                bool changed = false;
 
                assure_doms(irg);
@@ -912,16 +835,7 @@ static ir_graph_state_t do_cfopt(ir_graph *irg)
                 * Finally it marks all blocks that do not contain useful
                 * computations, i.e., these blocks might be removed.
                 */
-               switch_conds = NEW_ARR_F(ir_node*, 0);
-               irg_walk(end, clear_link_and_mark_blocks_removable, collect_nodes, &switch_conds);
-
-               /* handle all collected switch-Conds */
-               length = ARR_LEN(switch_conds);
-               for (i = 0; i < length; ++i) {
-                       ir_node *cond = switch_conds[i];
-                       changed |= handle_switch_cond(cond);
-               }
-               DEL_ARR_F(switch_conds);
+               irg_walk(end, clear_link_and_mark_blocks_removable, collect_nodes, NULL);
 
                if (!changed)
                        break;
index f6ae5d3..99616e9 100644 (file)
@@ -827,9 +827,10 @@ static void add_to_cprop(node_t *y, environment_t *env)
        if (y->on_cprop == 0) {
                partition_t *Y = y->part;
                ir_node *irn   = y->node;
+               ir_node *skipped = skip_Proj(irn);
 
                /* place Conds and all its Projs on the cprop_X list */
-               if (is_Cond(skip_Proj(irn)))
+               if (is_Cond(skipped) || is_Switch(skipped))
                        list_add_tail(&y->cprop_list, &Y->cprop_X);
                else
                        list_add_tail(&y->cprop_list, &Y->cprop);
@@ -2338,90 +2339,105 @@ static void compute_Proj_Cond(node_t *node, ir_node *cond)
        if (node->type.tv == tarval_reachable)
                return;
 
-       if (get_irn_mode(sel) == mode_b) {
-               /* an IF */
-               if (pnc == pn_Cond_true) {
-                       if (selector->type.tv == tarval_b_false) {
-                               node->type.tv = tarval_unreachable;
-                       } else if (selector->type.tv == tarval_b_true) {
-                               node->type.tv = tarval_reachable;
-                       } else if (selector->type.tv == tarval_bottom) {
-                               node->type.tv = tarval_reachable;
-                       } else {
-                               assert(selector->type.tv == tarval_top);
-                               if (tarval_UNKNOWN == tarval_top) {
-                                       /* any condition based on Top is "!=" */
-                                       node->type.tv = tarval_unreachable;
-                               } else {
-                                       node->type.tv = tarval_unreachable;
-                               }
-                       }
+       if (pnc == pn_Cond_true) {
+               if (selector->type.tv == tarval_b_false) {
+                       node->type.tv = tarval_unreachable;
+               } else if (selector->type.tv == tarval_b_true) {
+                       node->type.tv = tarval_reachable;
+               } else if (selector->type.tv == tarval_bottom) {
+                       node->type.tv = tarval_reachable;
                } else {
-                       assert(pnc == pn_Cond_false);
-
-                       if (selector->type.tv == tarval_b_false) {
-                               node->type.tv = tarval_reachable;
-                       } else if (selector->type.tv == tarval_b_true) {
+                       assert(selector->type.tv == tarval_top);
+                       if (tarval_UNKNOWN == tarval_top) {
+                               /* any condition based on Top is "!=" */
                                node->type.tv = tarval_unreachable;
-                       } else if (selector->type.tv == tarval_bottom) {
-                               node->type.tv = tarval_reachable;
                        } else {
-                               assert(selector->type.tv == tarval_top);
-                               if (tarval_UNKNOWN == tarval_top) {
-                                       /* any condition based on Top is "!=" */
-                                       node->type.tv = tarval_reachable;
-                               } else {
-                                       node->type.tv = tarval_unreachable;
-                               }
+                               node->type.tv = tarval_unreachable;
                        }
                }
        } else {
-               /* an SWITCH */
-               if (selector->type.tv == tarval_bottom) {
+               assert(pnc == pn_Cond_false);
+
+               if (selector->type.tv == tarval_b_false) {
+                       node->type.tv = tarval_reachable;
+               } else if (selector->type.tv == tarval_b_true) {
+                       node->type.tv = tarval_unreachable;
+               } else if (selector->type.tv == tarval_bottom) {
                        node->type.tv = tarval_reachable;
-               } else if (selector->type.tv == tarval_top) {
-                       if (tarval_UNKNOWN == tarval_top &&
-                           pnc == get_Cond_default_proj(cond)) {
-                               /* a switch based of Top is always "default" */
+               } else {
+                       assert(selector->type.tv == tarval_top);
+                       if (tarval_UNKNOWN == tarval_top) {
+                               /* any condition based on Top is "!=" */
                                node->type.tv = tarval_reachable;
                        } else {
                                node->type.tv = tarval_unreachable;
                        }
+               }
+       }
+}  /* compute_Proj_Cond */
+
+static void compute_Proj_Switch(node_t *node, ir_node *switchn)
+{
+       ir_node *proj     = node->node;
+       long     pnc      = get_Proj_proj(proj);
+       ir_node *sel      = get_Switch_selector(switchn);
+       node_t  *selector = get_irn_node(sel);
+
+       /* see long comment in compute_Proj_Cond */
+       if (node->type.tv == tarval_reachable)
+               return;
+
+       if (selector->type.tv == tarval_bottom) {
+               node->type.tv = tarval_reachable;
+       } else if (selector->type.tv == tarval_top) {
+               if (tarval_UNKNOWN == tarval_top && pnc == pn_Switch_default) {
+                       /* a switch based of Top is always "default" */
+                       node->type.tv = tarval_reachable;
                } else {
-                       long value = get_tarval_long(selector->type.tv);
-                       if (pnc == get_Cond_default_proj(cond)) {
-                               /* default switch, have to check ALL other cases */
-                               int i;
-
-                               for (i = get_irn_n_outs(cond) - 1; i >= 0; --i) {
-                                       ir_node *succ = get_irn_out(cond, i);
-
-                                       if (succ == proj)
-                                               continue;
-                                       if (value == get_Proj_proj(succ)) {
-                                               /* we found a match, will NOT take the default case */
-                                               node->type.tv = tarval_unreachable;
-                                               return;
-                                       }
+                       node->type.tv = tarval_unreachable;
+               }
+       } else {
+               long                   value = get_tarval_long(selector->type.tv);
+               const ir_switch_table *table = get_Switch_table(switchn);
+               size_t                 n_entries = ir_switch_table_get_n_entries(table);
+               size_t                 e;
+
+               for (e = 0; e < n_entries; ++e) {
+                       const ir_switch_table_entry *entry
+                               = ir_switch_table_get_entry_const(table, e);
+                       ir_tarval *min = entry->min;
+                       ir_tarval *max = entry->max;
+                       if (min == max) {
+                               if (selector->type.tv == min) {
+                                       node->type.tv = entry->pn == pnc
+                                               ? tarval_reachable : tarval_unreachable;
+                                       return;
                                }
-                               /* all cases checked, no match, will take default case */
-                               node->type.tv = tarval_reachable;
                        } else {
-                               /* normal case */
-                               node->type.tv = value == pnc ? tarval_reachable : tarval_unreachable;
+                               long minval = get_tarval_long(min);
+                               long maxval = get_tarval_long(max);
+                               if (minval <= value && value <= maxval) {
+                                       node->type.tv = entry->pn == pnc
+                                               ? tarval_reachable : tarval_unreachable;
+                                       return;
+                               }
                        }
                }
+
+               /* no entry matched: default */
+               node->type.tv
+                       = pnc == pn_Switch_default ? tarval_reachable : tarval_unreachable;
        }
-}  /* compute_Proj_Cond */
+}
 
 /**
- * (Re-)compute the type for a Proj-Node.
- *
- * @param node  the node
- */
+* (Re-)compute the type for a Proj-Node.
+*
+* @param node  the node
+*/
 static void compute_Proj(node_t *node)
 {
-       ir_node *proj = node->node;
+ir_node *proj = node->node;
        ir_mode *mode = get_irn_mode(proj);
        node_t  *block = get_irn_node(get_nodes_block(skip_Proj(proj)));
        ir_node *pred  = get_Proj_pred(proj);
@@ -2431,7 +2447,7 @@ static void compute_Proj(node_t *node)
                node->type.tv = tarval_top;
                return;
        }
-       if (get_irn_node(pred)->type.tv == tarval_top && !is_Cond(pred)) {
+       if (get_irn_node(pred)->type.tv == tarval_top && !is_Cond(pred) && !is_Switch(pred)) {
                /* if the predecessor is Top, its Proj follow */
                node->type.tv = tarval_top;
                return;
@@ -2452,6 +2468,9 @@ static void compute_Proj(node_t *node)
                case iro_Cond:
                        compute_Proj_Cond(node, pred);
                        return;
+               case iro_Switch:
+                       compute_Proj_Switch(node, pred);
+                       return;
                default:
                        break;
                }
@@ -3304,7 +3323,7 @@ static void apply_result(ir_node *irn, void *ctx)
                                /* leave or Jmp */
                                ir_node *cond = get_Proj_pred(irn);
 
-                               if (is_Cond(cond)) {
+                               if (is_Cond(cond) || is_Switch(cond)) {
                                        if (only_one_reachable_proj(cond)) {
                                                ir_node *jmp = new_r_Jmp(block->node);
                                                set_irn_node(jmp, node);
@@ -3314,14 +3333,16 @@ static void apply_result(ir_node *irn, void *ctx)
                                                exchange(irn, jmp);
                                                env->modified = 1;
                                        } else {
-                                               node_t    *sel = get_irn_node(get_Cond_selector(cond));
-                                               ir_tarval *tv  = sel->type.tv;
-
-                                               if (is_tarval(tv) && tarval_is_constant(tv)) {
-                                                       /* The selector is a constant, but more
-                                                        * than one output is active: An unoptimized
-                                                        * case found. */
-                                                       env->unopt_cf = 1;
+                                               if (is_Switch(cond)) {
+                                                       node_t    *sel = get_irn_node(get_Switch_selector(cond));
+                                                       ir_tarval *tv  = sel->type.tv;
+
+                                                       if (is_tarval(tv) && tarval_is_constant(tv)) {
+                                                               /* The selector is a constant, but more
+                                                                * than one output is active: An unoptimized
+                                                                * case found. */
+                                                               env->unopt_cf = 1;
+                                                       }
                                                }
                                        }
                                }
index 3b4dccd..5b9a83b 100644 (file)
@@ -197,37 +197,24 @@ unreachable_X:
                                } else if (is_Cond(pred)) {
                                        ir_node*   const selector = get_Cond_selector(pred);
                                        bitinfo*   const b        = get_bitinfo(selector);
-                                       if (is_undefined(b)) {
+                                       if (is_undefined(b))
                                                goto unreachable_X;
-                                       } else if (get_irn_mode(selector) == mode_b) {
-                                               if (b->z == b->o) {
-                                                       if ((b->z == t) == get_Proj_proj(irn)) {
-                                                               z = o = t;
-                                                       } else {
-                                                               z = o = f;
-                                                       }
+                                       if (b->z == b->o) {
+                                               if ((b->z == t) == get_Proj_proj(irn)) {
+                                                       z = o = t;
                                                } else {
-                                                       goto result_unknown_X;
+                                                       z = o = f;
                                                }
                                        } else {
-                                               long const val = get_Proj_proj(irn);
-                                               if (val != get_Cond_default_proj(pred)) {
-                                                       ir_tarval* const tv = new_tarval_from_long(val, get_irn_mode(selector));
-                                                       if (!tarval_is_null(tarval_andnot(tv, b->z)) ||
-                                                                       !tarval_is_null(tarval_andnot(b->o, tv))) {
-                                                               // At least one bit differs.
-                                                               z = o = f;
-#if 0 // TODO must handle default Proj
-                                                       } else if (b->z == b->o && b->z == tv) {
-                                                               z = o = t;
-#endif
-                                                       } else {
-                                                               goto result_unknown_X;
-                                                       }
-                                               } else {
-                                                       goto cannot_analyse_X;
-                                               }
+                                               goto result_unknown_X;
                                        }
+                               } else if (is_Switch(pred)) {
+                                       ir_node* const selector = get_Switch_selector(pred);
+                                       bitinfo* const b        = get_bitinfo(selector);
+                                       if (is_undefined(b))
+                                               goto unreachable_X;
+                                       /* TODO */
+                                       goto cannot_analyse_X;
                                } else {
                                        goto cannot_analyse_X;
                                }
index e8a245d..33c3f95 100644 (file)
@@ -295,7 +295,7 @@ static void copy_and_fix(const jumpthreading_env_t *env, ir_node *block,
                }
                /* ignore control flow */
                mode = get_irn_mode(node);
-               if (mode == mode_X || is_Cond(node))
+               if (mode == mode_X || is_Cond(node) || is_Switch(node))
                        continue;
 #ifdef AVOID_PHIB
                /* we may not copy mode_b nodes, because this could produce Phi with
@@ -348,7 +348,7 @@ static void copy_and_fix(const jumpthreading_env_t *env, ir_node *block,
                ir_mode *mode;
 
                mode = get_irn_mode(node);
-               if (mode == mode_X || is_Cond(node))
+               if (mode == mode_X || is_Cond(node) || is_Switch(node))
                        continue;
 #ifdef AVOID_PHIB
                if (mode == mode_b)
@@ -655,15 +655,12 @@ static void thread_jumps(ir_node* block, void* data)
        assert(get_irn_mode(projx) == mode_X);
 
        cond = get_Proj_pred(projx);
-       if (!is_Cond(cond))
-               return;
-
-       selector = get_Cond_selector(cond);
        /* TODO handle switch Conds */
-       if (get_irn_mode(selector) != mode_b)
+       if (!is_Cond(cond))
                return;
 
        /* handle cases that can be immediately evaluated */
+       selector = get_Cond_selector(cond);
        selector_evaluated = -1;
        if (is_Cmp(selector)) {
                ir_node *left  = get_Cmp_left(selector);
index bb78c9b..061f1f1 100755 (executable)
@@ -213,7 +213,6 @@ class Bound(Op):
        pinned_init = "op_pin_state_pinned"
        throws_init = "false"
        attr_struct = "bound_attr"
-       attrs_name  = "bound"
 
 class Builtin(Op):
        """performs a backend-specific builtin."""
@@ -317,18 +316,10 @@ class Cmp(Binop):
        attr_struct = "cmp_attr"
 
 class Cond(Op):
-       """Conditionally change control flow. There are two versions of this node:
-
-       Boolean Cond:
+       """Conditionally change control flow.
        Input:  A value of mode_b
        Output: A tuple of two control flows. The first is taken if the input is
                false, the second if it is true.
-
-       Switch Cond:
-       Input:  A value of mode_Iu
-       Output: A tuple of n control flows. If the Cond's input is i, control flow
-       will proceed along output i. If the input is >= n control flow proceeds
-       along output def_proj.
        """
        ins      = [
                ("selector",  "condition parameter"),
@@ -340,21 +331,42 @@ class Cond(Op):
        flags    = [ "cfopcode", "forking" ]
        pinned   = "yes"
        attrs    = [
-               dict(
-                       name    = "default_proj",
-                       type    = "long",
-                       init    = "0",
-                       comment = "Proj-number of default case for switch-Cond",
-               ),
                dict(
                        name    = "jmp_pred",
                        type    = "cond_jmp_predicate",
                        init    = "COND_JMP_PRED_NONE",
                        comment = "can indicate the most likely jump",
-               )
+               ),
        ]
        attr_struct = "cond_attr"
 
+class Switch(Op):
+       """Change control flow. The destination is choosen based on an integer input value which is looked up in a table.
+
+       Backends can implement this efficiently using a jump table."""
+       ins    = [
+               ("selector", "input selector"),
+       ]
+       outs   = [
+               ("default", "control flow if no other case matches"),
+       ]
+       flags  = [ "cfopcode", "forking" ]
+       pinned = "yes"
+       attrs  = [
+               dict(
+                       name    = "n_outs",
+                       type    = "unsigned",
+                       comment = "number of outputs (including pn_Switch_default)",
+               ),
+               dict(
+                       name    = "table",
+                       type    = "ir_switch_table*",
+                       comment = "table describing mapping from input values to Proj numbers",
+               ),
+       ]
+       attr_struct = "switch_attr"
+       attrs_name  = "switcha"
+
 class Confirm(Op):
        """Specifies constraints for a value. This allows explicit representation
        of path-sensitive properties. (Example: This value is always >= 0 on 1
@@ -380,7 +392,6 @@ class Confirm(Op):
                ),
        ]
        attr_struct = "confirm_attr"
-       attrs_name  = "confirm"
 
 class Const(Op):
        """Returns a constant value."""
@@ -411,7 +422,6 @@ class Conv(Unop):
                )
        ]
        attr_struct = "conv_attr"
-       attrs_name  = "conv"
 
 class CopyB(Op):
        """Copies a block of memory"""
@@ -434,7 +444,6 @@ class CopyB(Op):
                )
        ]
        attr_struct = "copyb_attr"
-       attrs_name  = "copyb"
        pinned      = "memory"
        pinned_init = "op_pin_state_pinned"
        throws_init = "false"
@@ -453,7 +462,6 @@ class Div(Op):
                ("X_except",  "control flow when exception occured"),
        ]
        flags = [ "fragile", "uses_memory" ]
-       attrs_name = "div"
        attrs = [
                dict(
                        type    = "ir_mode*",
@@ -641,7 +649,6 @@ class Mod(Op):
                ("X_except",  "control flow when exception occured"),
        ]
        flags = [ "fragile", "uses_memory" ]
-       attrs_name = "mod"
        attrs = [
                dict(
                        type    = "ir_mode*",