+ qsort(cases, num_cases, sizeof(cases[0]), casecmp);
+
+ info->default_block = targets[pn_Switch_default];
+ info->cases = cases;
+ free(targets);
+}
+
+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_max -= info->switch_min;
+ info->switch_min = 0;
+ }
+
+ 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);