Set the pinned state to float if we can detect that no exception can arise
[libfirm] / ir / ir / irarch.c
index 255a222..4f43bc6 100644 (file)
@@ -6,7 +6,6 @@
  *
  * $Id$
  */
-
 #include <stdlib.h>
 #include <assert.h>
 
 #include "firmstat.h"
 #include "ircons.h"
 #include "irarch.h"
-
+#include "firmstat.h"
 
 #undef DEB
 
 #define MAX_BITSTR 64
 
-/** The params got from the factopry in arch_dep_init(...). */
+/** The params got from the factory in arch_dep_init(...). */
 static const arch_dep_params_t *params = NULL;
 
 /** The bit mask, which optimizations to apply. */
@@ -51,22 +50,19 @@ void arch_dep_set_opts(arch_dep_opts_t the_opts) {
 ir_node *arch_dep_replace_mul_with_shifts(ir_node *irn)
 {
   ir_node *res = irn;
-  ir_node *operand = NULL;
-  ir_node *left, *right;
   ir_mode *mode = get_irn_mode(irn);
-  tarval *tv = NULL;
 
   /* If the architecture dependent optimizations were not initialized
      or this optimization was not enabled. */
   if(params == NULL || (opts & arch_dep_mul_to_shift) == 0)
     return irn;
 
-  if(is_ir_node(irn)
-     && get_irn_opcode(irn) == iro_Mul
-     && mode_is_int(mode)) {
-
-    left = get_binop_left(irn);
-    right = get_binop_right(irn);
+  if(get_irn_opcode(irn) == iro_Mul && mode_is_int(mode)) {
+    ir_node *block   = get_nodes_block(irn);
+    ir_node *left    = get_binop_left(irn);
+    ir_node *right   = get_binop_right(irn);
+    tarval *tv       = NULL;
+    ir_node *operand = NULL;
 
     /* Look, if one operand is a constant. */
     if(get_irn_opcode(left) == iro_Const) {
@@ -99,38 +95,37 @@ ir_node *arch_dep_replace_mul_with_shifts(ir_node *irn)
 
 #if DEB
       {
-       int val = (int) get_tarval_long(tv);
-       fprintf(stderr, "Found mul with %d(%x) = ", val, val);
-       for(p = bitstr; *p != '\0'; p++)
-         printf("%c", *p);
-       printf("\n");
+        long val = get_tarval_long(tv);
+        fprintf(stderr, "Found mul with %ld(%lx) = ", val, val);
+        for(p = bitstr; *p != '\0'; p++)
+          printf("%c", *p);
+        printf("\n");
       }
 #endif
 
       for(p = bitstr; *p != '\0'; p++) {
-       int bit = *p != '0';
-
-       switch(bit - last) {
-       case -1:          // The last was 1 we are now at 0
-       case 1:           // The last was 0 and we are now at 1
-         compr[compr_len++] = counter;
-         counter = 1;
-         break;
-       default:
-         counter++;
-       }
-
-       last = bit;
+        int bit = *p != '0';
+
+        if (bit != last) {
+          /* The last was 1 we are now at 0 OR
+           * The last was 0 and we are now at 1 */
+          compr[compr_len++] = counter;
+          counter = 1;
+        }
+        else
+          counter++;
+
+        last = bit;
       }
       compr[compr_len++] = counter;
 
 
-#ifdef DEF
+#ifdef DEB
       {
-       const char *prefix = "";
-       for(i = 0; i < compr_len; i++, prefix = ",")
-         fprintf(stderr, "%s%d", prefix, compr[i]);
-       fprintf("\n");
+        const char *prefix = "";
+        for(i = 0; i < compr_len; i++, prefix = ",")
+          fprintf(stderr, "%s%d", prefix, compr[i]);
+        fprintf("\n");
       }
 #endif
 
@@ -138,164 +133,410 @@ ir_node *arch_dep_replace_mul_with_shifts(ir_node *irn)
       curr_bit = compr[0];
 
       for(i = 1; i < compr_len; i = end_of_group + 2) {
-       int j, zeros_in_group, ones_in_group;
+        int j, zeros_in_group, ones_in_group;
 
-       ones_in_group = compr[i];
-       zeros_in_group = 0;
+        ones_in_group = compr[i];
+        zeros_in_group = 0;
 
-       // Scan for singular 0s in a sequence
-       for(j = i + 1; j < compr_len && compr[j] == 1; j += 2) {
-         zeros_in_group += 1;
-         ones_in_group += (j + 1 < compr_len ? compr[j + 1] : 0);
-       }
-       end_of_group = j - 1;
+        // Scan for singular 0s in a sequence
+        for(j = i + 1; j < compr_len && compr[j] == 1; j += 2) {
+          zeros_in_group += 1;
+          ones_in_group += (j + 1 < compr_len ? compr[j + 1] : 0);
+        }
+        end_of_group = j - 1;
 
-       if(zeros_in_group >= ones_in_group - 1)
-         end_of_group = i;
+        if(zeros_in_group >= ones_in_group - 1)
+          end_of_group = i;
 
 #ifdef DEB
-       fprintf(stderr, "  i:%d, eg:%d\n", i, end_of_group);
+        fprintf(stderr, "  i:%d, eg:%d\n", i, end_of_group);
 #endif
 
-       singleton = compr[i] == 1 && i == end_of_group;
-       for(j = i; j <= end_of_group; j += 2) {
-         int curr_ones = compr[j];
-         int biased_curr_bit = curr_bit + 1;
-         int k;
+        singleton = compr[i] == 1 && i == end_of_group;
+        for(j = i; j <= end_of_group; j += 2) {
+          int curr_ones = compr[j];
+          int biased_curr_bit = curr_bit + 1;
+          int k;
 
 #ifdef DEB
-         fprintf(stderr, "    j:%d, ones:%d\n", j, curr_ones);
+          fprintf(stderr, "    j:%d, ones:%d\n", j, curr_ones);
 #endif
 
-         // If this ones group is a singleton group (it has no
-         // singleton zeros inside
-         if(singleton)
-           shift_with_sub[shift_with_sub_pos++] = biased_curr_bit;
-         else if(j == i)
-           shift_with_sub[shift_with_sub_pos++] = -biased_curr_bit;
+          // If this ones group is a singleton group (it has no
+          // singleton zeros inside
+          if(singleton)
+            shift_with_sub[shift_with_sub_pos++] = biased_curr_bit;
+          else if(j == i)
+            shift_with_sub[shift_with_sub_pos++] = -biased_curr_bit;
 
-         for(k = 0; k < curr_ones; k++)
-           shift_without_sub[shift_without_sub_pos++] = biased_curr_bit + k;
+          for(k = 0; k < curr_ones; k++)
+            shift_without_sub[shift_without_sub_pos++] = biased_curr_bit + k;
 
-         curr_bit += curr_ones;
-         biased_curr_bit = curr_bit + 1;
+          curr_bit += curr_ones;
+          biased_curr_bit = curr_bit + 1;
 
-         if(!singleton && j == end_of_group)
-           shift_with_sub[shift_with_sub_pos++] = biased_curr_bit;
-         else if(j != end_of_group)
-           shift_with_sub[shift_with_sub_pos++] = -biased_curr_bit;
+          if(!singleton && j == end_of_group)
+            shift_with_sub[shift_with_sub_pos++] = biased_curr_bit;
+          else if(j != end_of_group)
+            shift_with_sub[shift_with_sub_pos++] = -biased_curr_bit;
 
-         curr_bit += compr[j + 1];
-       }
+          curr_bit += compr[j + 1];
+        }
 
       }
 
       {
-       int *shifts = shift_with_sub;
-       int n = shift_with_sub_pos;
-       int highest_shift_wide = 0;
-       int highest_shift_seq = 0;
-       int last_shift = 0;
-
-       /* If we may not use subs, or we can achive the same with adds,
-          prefer adds. */
-       if(!also_use_subs || shift_with_sub_pos >= shift_without_sub_pos) {
-         shifts = shift_without_sub;
-         n = shift_without_sub_pos;
-       }
-
-       /* If the number of needed shifts exceeds the given maximum,
-          use the Mul and exit. */
-       if(n > maximum_shifts) {
+        int *shifts = shift_with_sub;
+        int n = shift_with_sub_pos;
+        int highest_shift_wide = 0;
+        int highest_shift_seq = 0;
+        int last_shift = 0;
+
+        /* If we may not use subs, or we can achive the same with adds,
+           prefer adds. */
+        if(!also_use_subs || shift_with_sub_pos >= shift_without_sub_pos) {
+          shifts = shift_without_sub;
+          n = shift_without_sub_pos;
+        }
+
+        /* If the number of needed shifts exceeds the given maximum,
+           use the Mul and exit. */
+        if(n > maximum_shifts) {
 #ifdef DEB
-         fprintf(stderr, "Only allowed %d shifts, but %d are needed\n",
-                 maximum_shifts, n);
+          fprintf(stderr, "Only allowed %d shifts, but %d are needed\n",
+              maximum_shifts, n);
 #endif
-         return irn;
-       }
-
-       /* Compute the highest shift needed for both, the
-          sequential and wide representations. */
-       for(i = 0; i < n; i++) {
-         int curr = abs(shifts[i]);
-         int curr_seq = curr - last;
-
-         highest_shift_wide = curr > highest_shift_wide ? curr
-           : highest_shift_wide;
-         highest_shift_seq = curr_seq > highest_shift_seq ? curr_seq
-           : highest_shift_seq;
-
-         last_shift = curr;
-       }
-
-       /* If the highest shift amount is greater than the given limit,
-          give back the Mul */
-       if(highest_shift_seq > highest_shift_amount) {
+          return irn;
+        }
+
+        /* Compute the highest shift needed for both, the
+           sequential and wide representations. */
+        for(i = 0; i < n; i++) {
+          int curr = abs(shifts[i]);
+          int curr_seq = curr - last;
+
+          highest_shift_wide = curr > highest_shift_wide ? curr
+            : highest_shift_wide;
+          highest_shift_seq = curr_seq > highest_shift_seq ? curr_seq
+            : highest_shift_seq;
+
+          last_shift = curr;
+        }
+
+        /* If the highest shift amount is greater than the given limit,
+           give back the Mul */
+        if(highest_shift_seq > highest_shift_amount) {
 #ifdef DEB
-         fprintf(stderr, "Shift argument %d exceeds maximum %d\n",
-                 highest_shift_seq, highest_shift_amount);
+          fprintf(stderr, "Shift argument %d exceeds maximum %d\n",
+              highest_shift_seq, highest_shift_amount);
 #endif
-         return irn;
-       }
+          return irn;
+        }
 
-       /* If we have subs, we cannot do sequential. */
-       if(1 /* also_use_subs */) {
-         if(n > 0) {
-           ir_node *curr = NULL;
+        /* If we have subs, we cannot do sequential. */
+        if(1 /* also_use_subs */) {
+          if(n > 0) {
+            ir_node *curr = NULL;
 
-           i = n - 1;
+            i = n - 1;
 
-           do {
-             int curr_shift = shifts[i];
-             int sub = curr_shift < 0;
-             int amount = abs(curr_shift) - 1;
-             ir_node *aux = operand;
+            do {
+              int curr_shift = shifts[i];
+              int sub = curr_shift < 0;
+              int amount = abs(curr_shift) - 1;
+              ir_node *aux = operand;
 
 
-             assert(amount >= 0 && "What is a negative shift??");
+              assert(amount >= 0 && "What is a negative shift??");
 
-             if(amount != 0) {
-               tarval *shift_amount = new_tarval_from_long(amount, mode_Iu);
-               ir_node *cnst = new_Const(mode_Iu, shift_amount);
-               aux = new_Shl(operand, cnst, mode);
-             }
+              if(amount != 0) {
+                tarval *shift_amount = new_tarval_from_long(amount, mode_Iu);
+                ir_node *cnst = new_r_Const(current_ir_graph, block, mode_Iu, shift_amount);
+                aux = new_r_Shl(current_ir_graph, block, operand, cnst, mode);
+              }
 
-             if(curr) {
-               if(sub)
-                 curr = new_Sub(curr, aux, mode);
-               else
-                 curr = new_Add(curr, aux, mode);
-             } else
-               curr = aux;
+              if(curr) {
+                if(sub)
+                  curr = new_r_Sub(current_ir_graph, block, curr, aux, mode);
+                else
+                  curr = new_r_Add(current_ir_graph, block, curr, aux, mode);
+              } else
+                curr = aux;
 
-           } while(--i >= 0);
+            } while(--i >= 0);
 
-           res = curr;
-         }
-       }
+            res = curr;
+          }
+        }
 
 #ifdef DEB
-       {
-         const char *prefix = "";
-         for(i = 0; i < n; i++) {
-           fprintf(stderr, "%s%d", prefix, shifts[i]);
-           prefix = ", ";
-         }
-         fprintf(stderr, "\n");
-       }
+        {
+          const char *prefix = "";
+          for(i = 0; i < n; i++) {
+            fprintf(stderr, "%s%d", prefix, shifts[i]);
+            prefix = ", ";
+          }
+          fprintf(stderr, "\n");
+        }
 #endif
 
       }
 
       if(bitstr)
-       free(bitstr);
+        free(bitstr);
+    }
+
+  }
+
+  if (res != irn)
+    stat_arch_dep_replace_mul_with_shifts(irn);
+
+  return res;
+}
+
+ir_node *arch_dep_replace_div_with_shifts(ir_node *irn)
+{
+  ir_node *res  = irn;
+
+  /* If the architecture dependent optimizations were not initialized
+     or this optimization was not enabled. */
+  if (params == NULL || (opts & arch_dep_div_to_shift) == 0)
+    return irn;
+
+  if (get_irn_opcode(irn) == iro_Div) {
+    ir_node *c = get_Div_right(irn);
+    ir_node *block, *left;
+    ir_mode *mode;
+    tarval *tv;
+    dbg_info *dbg;
+    int n, bits;
+    int i, k, num;
+
+    if (get_irn_op(c) != op_Const)
+      return irn;
+
+    left  = get_Div_left(irn);
+    mode  = get_irn_mode(left);
+    block = get_nodes_block(irn);
+    dbg   = get_irn_dbg_info(irn);
+    tv    = get_Const_tarval(c);
+
+    bits = get_mode_size_bits(mode);
+    n    = (bits + 7) / 8;
+
+    for (num = i = 0; i < n; ++i) {
+      unsigned char v = get_tarval_sub_bits(tv, i);
+
+      if (v) {
+        int j;
+
+        for (j = 0; j < 8; ++j)
+          if ((1 << j) & v) {
+            ++num;
+            k = 8 * i + j;
+          }
+      }
+    }
+
+    if (num == 1) { /* division by 2^k */
+
+      if (mode_is_signed(mode)) {
+        ir_node *k_node;
+        ir_node *curr = left;
+
+        if (k != 1) {
+          k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(k - 1, mode_Iu));
+          curr   = new_rd_Shrs(dbg, current_ir_graph, block, left, k_node, mode);
+        }
+
+        k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(bits - k, mode_Iu));
+        curr   = new_rd_Shr(dbg, current_ir_graph, block, curr, k_node, mode);
+
+        curr   = new_rd_Add(dbg, current_ir_graph, block, left, curr, mode);
+
+        k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(k, mode_Iu));
+        res    = new_rd_Shrs(dbg, current_ir_graph, block, curr, k_node, mode);
+      }
+      else {      /* unsigned case */
+        ir_node *k_node;
+
+        k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(k, mode_Iu));
+        res    = new_rd_Shl(dbg, current_ir_graph, block, left, k_node, mode);
+      }
+    }
+  }
+
+  if (res != irn)
+    stat_arch_dep_replace_div_with_shifts(irn);
+
+  return res;
+}
+
+ir_node *arch_dep_replace_mod_with_shifts(ir_node *irn)
+{
+  ir_node *res  = irn;
+
+  /* If the architecture dependent optimizations were not initialized
+     or this optimization was not enabled. */
+  if (params == NULL || (opts & arch_dep_mod_to_shift) == 0)
+    return irn;
+
+  if (get_irn_opcode(irn) == iro_Mod) {
+    ir_node *c = get_Mod_right(irn);
+    ir_node *block, *left;
+    ir_mode *mode;
+    tarval *tv;
+    dbg_info *dbg;
+    int n, bits;
+    int i, k, num;
+
+    if (get_irn_op(c) != op_Const)
+      return irn;
+
+    left  = get_Mod_left(irn);
+    mode  = get_irn_mode(left);
+    block = get_nodes_block(irn);
+    dbg   = get_irn_dbg_info(irn);
+    tv    = get_Const_tarval(c);
+
+    bits = get_mode_size_bits(mode);
+    n    = (bits + 7) / 8;
+
+    for (num = i = 0; i < n; ++i) {
+      unsigned char v = get_tarval_sub_bits(tv, i);
+
+      if (v) {
+        int j;
+
+        for (j = 0; j < 8; ++j)
+          if ((1 << j) & v) {
+            ++num;
+            k = 8 * i + j;
+          }
+      }
     }
 
+    if (num == 1) { /* remainder by 2^k */
+
+      if (mode_is_signed(mode)) {
+        ir_node *k_node;
+        ir_node *curr = left;
+
+        if (k != 1) {
+          k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(k - 1, mode_Iu));
+          curr   = new_rd_Shrs(dbg, current_ir_graph, block, left, k_node, mode);
+        }
+
+        k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(bits - k, mode_Iu));
+        curr   = new_rd_Shr(dbg, current_ir_graph, block, curr, k_node, mode);
+
+        curr   = new_rd_Add(dbg, current_ir_graph, block, left, curr, mode);
+
+        k_node = new_r_Const(current_ir_graph, block, mode, new_tarval_from_long((-1) << k, mode));
+        curr   = new_rd_And(dbg, current_ir_graph, block, curr, k_node, mode);
+
+        res    = new_rd_Sub(dbg, current_ir_graph, block, left, curr, mode);
+      }
+      else {      /* unsigned case */
+        ir_node *k_node;
+
+        k_node = new_r_Const(current_ir_graph, block, mode, new_tarval_from_long((1 << k) - 1, mode));
+        res    = new_rd_And(dbg, current_ir_graph, block, left, k_node, mode);
+      }
+    }
   }
 
+  if (res != irn)
+    stat_arch_dep_replace_mod_with_shifts(irn);
+
   return res;
 }
 
+void arch_dep_replace_divmod_with_shifts(ir_node **div, ir_node **mod, ir_node *irn)
+{
+  *div = *mod = NULL;
+
+  /* If the architecture dependent optimizations were not initialized
+     or this optimization was not enabled. */
+  if (params == NULL ||
+      ((opts & (arch_dep_div_to_shift|arch_dep_mod_to_shift)) != (arch_dep_div_to_shift|arch_dep_mod_to_shift)))
+    return;
+
+  if (get_irn_opcode(irn) == iro_DivMod) {
+    ir_node *c = get_DivMod_right(irn);
+    ir_node *block, *left;
+    ir_mode *mode;
+    tarval *tv;
+    dbg_info *dbg;
+    int n, bits;
+    int i, k, num;
+
+    if (get_irn_op(c) != op_Const)
+      return;
+
+    left  = get_DivMod_left(irn);
+    mode  = get_irn_mode(left);
+    block = get_nodes_block(irn);
+    dbg   = get_irn_dbg_info(irn);
+    tv    = get_Const_tarval(c);
+
+    bits = get_mode_size_bits(mode);
+    n    = (bits + 7) / 8;
+
+    for (num = i = 0; i < n; ++i) {
+      unsigned char v = get_tarval_sub_bits(tv, i);
+
+      if (v) {
+        int j;
+
+        for (j = 0; j < 8; ++j)
+          if ((1 << j) & v) {
+            ++num;
+            k = 8 * i + j;
+          }
+      }
+    }
+
+    if (num == 1) { /* division & remainder by 2^k */
+
+      if (mode_is_signed(mode)) {
+        ir_node *k_node;
+        ir_node *curr = left;
+
+        if (k != 1) {
+          k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(k - 1, mode_Iu));
+          curr   = new_rd_Shrs(dbg, current_ir_graph, block, left, k_node, mode);
+        }
+
+        k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(bits - k, mode_Iu));
+        curr   = new_rd_Shr(dbg, current_ir_graph, block, curr, k_node, mode);
+
+        curr   = new_rd_Add(dbg, current_ir_graph, block, left, curr, mode);
+
+        k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(k, mode_Iu));
+        *div   = new_rd_Shrs(dbg, current_ir_graph, block, curr, k_node, mode);
+
+        k_node = new_r_Const(current_ir_graph, block, mode, new_tarval_from_long((-1) << k, mode));
+        curr   = new_rd_And(dbg, current_ir_graph, block, curr, k_node, mode);
+
+        *mod   = new_rd_Sub(dbg, current_ir_graph, block, left, curr, mode);
+      }
+      else {      /* unsigned case */
+        ir_node *k_node;
+
+        k_node = new_r_Const(current_ir_graph, block, mode_Iu, new_tarval_from_long(k, mode_Iu));
+        *div   = new_rd_Shl(dbg, current_ir_graph, block, left, k_node, mode);
+
+        k_node = new_r_Const(current_ir_graph, block, mode, new_tarval_from_long((1 << k) - 1, mode));
+        *mod   = new_rd_And(dbg, current_ir_graph, block, left, k_node, mode);
+      }
+    }
+  }
+
+  if (*div)
+    stat_arch_dep_replace_DivMod_with_shifts(irn);
+}
+
 
 static const arch_dep_params_t default_params = {
   1, /* also use subs */