Small improvement: lower a double word x << 1 into x + x, saves one instruction on...
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Fri, 8 Oct 2010 21:44:42 +0000 (21:44 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Fri, 8 Oct 2010 21:44:42 +0000 (21:44 +0000)
[r28086]

ir/lower/lower_dw.c

index fc24297..678e87b 100644 (file)
@@ -748,31 +748,59 @@ static void lower_Shl(ir_node *node, ir_mode *mode, lower_env_t *env)
        if (get_mode_arithmetic(mode) == irma_twos_complement && is_Const(right)) {
                ir_tarval *tv = get_Const_tarval(right);
 
-               if (tarval_is_long(tv) &&
-                   get_tarval_long(tv) >= (long)get_mode_size_bits(mode)) {
-                       ir_mode *mode_l;
-                       ir_node *block = get_nodes_block(node);
-                       ir_node *left = get_Shl_left(node);
-                       ir_node *c;
-                       long shf_cnt = get_tarval_long(tv) - get_mode_size_bits(mode);
-                       const node_entry_t *left_entry = get_node_entry(env, left);
-                       ir_node  *res_low;
-                       ir_node  *res_high;
+               if (tarval_is_long(tv)) {
+                       long value = get_tarval_long(tv);
+                   if (value >= (long)get_mode_size_bits(mode)) {
+                               /* simple case: shift above the lower word */
+                               ir_mode *mode_l;
+                               ir_node *block = get_nodes_block(node);
+                               ir_node *left = get_Shl_left(node);
+                               ir_node *c;
+                               long shf_cnt = get_tarval_long(tv) - get_mode_size_bits(mode);
+                               const node_entry_t *left_entry = get_node_entry(env, left);
+                               ir_node  *res_low;
+                               ir_node  *res_high;
 
-                       left = left_entry->low_word;
-                       left = new_r_Conv(block, left, mode);
+                               left = left_entry->low_word;
+                               left = new_r_Conv(block, left, mode);
 
-                       mode_l = env->low_unsigned;
-                       if (shf_cnt > 0) {
-                               c        = new_r_Const_long(irg, mode_l, shf_cnt);
-                               res_high = new_r_Shl(block, left, c, mode);
-                       } else {
-                               res_high = left;
-                       }
-                       res_low = new_r_Const(irg, get_mode_null(mode_l));
-                       set_lowered(env, node, res_low, res_high);
+                               mode_l = env->low_unsigned;
+                               if (shf_cnt > 0) {
+                                       c        = new_r_Const_long(irg, mode_l, shf_cnt);
+                                       res_high = new_r_Shl(block, left, c, mode);
+                               } else {
+                                       res_high = left;
+                               }
+                               res_low = new_r_Const(irg, get_mode_null(mode_l));
+                               set_lowered(env, node, res_low, res_high);
 
-                       return;
+                               return;
+                       }
+                       if (value == 1) {
+                               /* left << 1 == left + left */
+                               ir_node            *left        = get_binop_left(node);
+                               const node_entry_t *left_entry  = get_node_entry(env, left);
+                               ir_node            *in[4]       = {
+                                       left_entry->low_word, left_entry->high_word,
+                                       left_entry->low_word, left_entry->high_word,
+                               };
+                               dbg_info           *dbgi        = get_irn_dbg_info(node);
+                               ir_node            *block       = get_nodes_block(node);
+                               ir_graph           *irg         = get_irn_irg(block);
+                               ir_type            *mtp
+                                       = mode_is_signed(mode) ? binop_tp_s : binop_tp_u;
+                               ir_node            *addr
+                                       = get_intrinsic_address(mtp, op_Add, mode, mode, env);
+                               ir_node            *call
+                                       = new_rd_Call(dbgi, block, get_irg_no_mem(irg), addr, 4, in, mtp);
+                               ir_node            *resproj  = new_r_Proj(call, mode_T, pn_Call_T_result);
+                               ir_node            *res_low  = new_r_Proj(resproj, env->low_unsigned, 0);
+                               ir_node            *res_high = new_r_Proj(resproj, mode,              1);
+                               set_irn_pinned(call, get_irn_pinned(node));
+                               set_lowered(env, node, res_low, res_high);
+
+                               return;
+                       }
                }
        }
        lower_Shiftop(node, mode, env);