fixed sign extensions - added explicit side effect op flag - added discard instruction


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3963 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/tcg/README b/tcg/README
index 466e330..fd72cad 100644
--- a/tcg/README
+++ b/tcg/README
@@ -280,6 +280,11 @@
 
 64 bit byte swap
 
+* discard_i32/i64 t0
+
+Indicate that the value of t0 won't be used later. It is useful to
+force dead code elimination.
+
 ********* Type conversions
 
 * ext_i32_i64 t0, t1
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 6fb3138..82aebb3 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -865,7 +865,7 @@
     tcg_gen_op2(INDEX_op_ext8s_i32, ret, arg);
 #else
     tcg_gen_shli_i32(ret, arg, 24);
-    tcg_gen_sari_i32(ret, arg, 24);
+    tcg_gen_sari_i32(ret, ret, 24);
 #endif
 }
 
@@ -875,7 +875,7 @@
     tcg_gen_op2(INDEX_op_ext16s_i32, ret, arg);
 #else
     tcg_gen_shli_i32(ret, arg, 16);
-    tcg_gen_sari_i32(ret, arg, 16);
+    tcg_gen_sari_i32(ret, ret, 16);
 #endif
 }
 
@@ -975,7 +975,7 @@
     tcg_gen_op2(INDEX_op_ext8s_i64, ret, arg);
 #else
     tcg_gen_shli_i64(ret, arg, 56);
-    tcg_gen_sari_i64(ret, arg, 56);
+    tcg_gen_sari_i64(ret, ret, 56);
 #endif
 }
 
@@ -985,7 +985,7 @@
     tcg_gen_op2(INDEX_op_ext16s_i64, ret, arg);
 #else
     tcg_gen_shli_i64(ret, arg, 48);
-    tcg_gen_sari_i64(ret, arg, 48);
+    tcg_gen_sari_i64(ret, ret, 48);
 #endif
 }
 
@@ -995,7 +995,7 @@
     tcg_gen_op2(INDEX_op_ext32s_i64, ret, arg);
 #else
     tcg_gen_shli_i64(ret, arg, 32);
-    tcg_gen_sari_i64(ret, arg, 32);
+    tcg_gen_sari_i64(ret, ret, 32);
 #endif
 }
 
@@ -1062,6 +1062,25 @@
 
 #endif
 
+
+static inline void tcg_gen_discard_i32(TCGv arg)
+{
+    tcg_gen_op1(INDEX_op_discard, arg);
+}
+
+#if TCG_TARGET_REG_BITS == 32
+static inline void tcg_gen_discard_i64(TCGv arg)
+{
+    tcg_gen_discard_i32(arg);
+    tcg_gen_discard_i32(TCGV_HIGH(arg));
+}
+#else
+static inline void tcg_gen_discard_i64(TCGv arg)
+{
+    tcg_gen_op1(INDEX_op_discard, arg);
+}
+#endif
+
 /***************************************/
 static inline void tcg_gen_macro_2(TCGv ret0, TCGv ret1, int macro_id)
 {
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index ebf4f82..4d91d11 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -40,10 +40,12 @@
 DEF2(macro_end, 0, 0, 2, 0)
 DEF2(macro_goto, 0, 0, 3, 0)
 
+DEF2(discard, 1, 0, 0, 0)
+
 DEF2(set_label, 0, 0, 1, 0)
-DEF2(call, 0, 1, 2, 0) /* variable number of parameters */
-DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END)
-DEF2(br, 0, 0, 1, TCG_OPF_BB_END)
+DEF2(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */
+DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF2(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 
 DEF2(mov_i32, 1, 1, 0, 0)
 DEF2(movi_i32, 1, 0, 1, 0)
@@ -53,9 +55,9 @@
 DEF2(ld16u_i32, 1, 1, 1, 0)
 DEF2(ld16s_i32, 1, 1, 1, 0)
 DEF2(ld_i32, 1, 1, 1, 0)
-DEF2(st8_i32, 0, 2, 1, 0)
-DEF2(st16_i32, 0, 2, 1, 0)
-DEF2(st_i32, 0, 2, 1, 0)
+DEF2(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF2(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF2(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
 /* arith */
 DEF2(add_i32, 1, 2, 0, 0)
 DEF2(sub_i32, 1, 2, 0, 0)
@@ -77,11 +79,11 @@
 DEF2(shr_i32, 1, 2, 0, 0)
 DEF2(sar_i32, 1, 2, 0, 0)
 
-DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END)
+DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 #if TCG_TARGET_REG_BITS == 32
 DEF2(add2_i32, 2, 4, 0, 0)
 DEF2(sub2_i32, 2, 4, 0, 0)
-DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END)
+DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 DEF2(mulu2_i32, 2, 2, 0, 0)
 #endif
 #ifdef TCG_TARGET_HAS_ext8s_i32
@@ -105,10 +107,10 @@
 DEF2(ld32u_i64, 1, 1, 1, 0)
 DEF2(ld32s_i64, 1, 1, 1, 0)
 DEF2(ld_i64, 1, 1, 1, 0)
-DEF2(st8_i64, 0, 2, 1, 0)
-DEF2(st16_i64, 0, 2, 1, 0)
-DEF2(st32_i64, 0, 2, 1, 0)
-DEF2(st_i64, 0, 2, 1, 0)
+DEF2(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF2(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF2(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF2(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
 /* arith */
 DEF2(add_i64, 1, 2, 0, 0)
 DEF2(sub_i64, 1, 2, 0, 0)
@@ -130,7 +132,7 @@
 DEF2(shr_i64, 1, 2, 0, 0)
 DEF2(sar_i64, 1, 2, 0, 0)
 
-DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END)
+DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 #ifdef TCG_TARGET_HAS_ext8s_i64
 DEF2(ext8s_i64, 1, 1, 0, 0)
 #endif
@@ -146,82 +148,82 @@
 #endif
 
 /* QEMU specific */
-DEF2(exit_tb, 0, 0, 1, TCG_OPF_BB_END)
-DEF2(goto_tb, 0, 0, 1, TCG_OPF_BB_END)
+DEF2(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF2(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 /* Note: even if TARGET_LONG_BITS is not defined, the INDEX_op
    constants must be defined */
 #if TCG_TARGET_REG_BITS == 32
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
-DEF2(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 
 #else /* TCG_TARGET_REG_BITS == 32 */
 
-DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
-DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
-DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
-DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
-DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
-DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
-DEF2(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF2(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 
-DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
-DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
-DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
-DEF2(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
+DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF2(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 
 #endif /* TCG_TARGET_REG_BITS != 32 */
 
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 76dd75e..55fe215 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -401,6 +401,7 @@
         ts = &s->temps[s->nb_temps];
         ts->base_type = type;
         ts->type = TCG_TYPE_I32;
+        ts->fixed_reg = 0;
         ts->val_type = TEMP_VAL_DEAD;
         ts->mem_allocated = 0;
         ts->name = NULL;
@@ -408,6 +409,7 @@
         ts->base_type = TCG_TYPE_I32;
         ts->type = TCG_TYPE_I32;
         ts->val_type = TEMP_VAL_DEAD;
+        ts->fixed_reg = 0;
         ts->mem_allocated = 0;
         ts->name = NULL;
         s->nb_temps += 2;
@@ -418,6 +420,7 @@
         ts = &s->temps[s->nb_temps];
         ts->base_type = type;
         ts->type = type;
+        ts->fixed_reg = 0;
         ts->val_type = TEMP_VAL_DEAD;
         ts->mem_allocated = 0;
         ts->name = NULL;
@@ -805,11 +808,12 @@
                 assert(oarg < def->nb_oargs);
                 assert(def->args_ct[oarg].ct & TCG_CT_REG);
                 /* TCG_CT_ALIAS is for the output arguments. The input
-                   argument is tagged with TCG_CT_IALIAS for
-                   informative purposes. */
+                   argument is tagged with TCG_CT_IALIAS. */
                 def->args_ct[i] = def->args_ct[oarg];
-                def->args_ct[oarg].ct = i | TCG_CT_ALIAS;
+                def->args_ct[oarg].ct = TCG_CT_ALIAS;
+                def->args_ct[oarg].alias_index = i;
                 def->args_ct[i].ct |= TCG_CT_IALIAS;
+                def->args_ct[i].alias_index = oarg;
             } else {
                 for(;;) {
                     if (*ct_str == '\0')
@@ -935,6 +939,11 @@
             nb_args = args[-1];
             args -= nb_args;
             break;
+        case INDEX_op_discard:
+            args--;
+            /* mark the temporary as dead */
+            dead_temps[args[0]] = 1;
+            break;
         case INDEX_op_macro_2:
             {
                 int dead_args[2], macro_id;
@@ -1015,12 +1024,9 @@
                 nb_oargs = def->nb_oargs;
 
                 /* Test if the operation can be removed because all
-                   its outputs are dead. We may add a flag to
-                   explicitely tell if the op has side
-                   effects. Currently we assume that if nb_oargs == 0
-                   or OPF_BB_END is set, the operation has side
-                   effects and cannot be removed */
-                if (nb_oargs != 0 && !(def->flags & TCG_OPF_BB_END)) {
+                   its outputs are dead. We assume that nb_oargs == 0
+                   implies side effects */
+                if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
                     for(i = 0; i < nb_oargs; i++) {
                         arg = args[i];
                         if (!dead_temps[arg])
@@ -1164,7 +1170,7 @@
     ts = &s->temps[temp];
     s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
     if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
-        abort();
+        tcg_abort();
     ts->mem_offset = s->current_frame_offset;
     ts->mem_reg = s->frame_reg;
     ts->mem_allocated = 1;
@@ -1350,12 +1356,19 @@
             }
         }
         assert(ts->val_type == TEMP_VAL_REG);
-        if ((arg_ct->ct & TCG_CT_IALIAS) &&
-            !IS_DEAD_IARG(i - nb_oargs)) {
-            /* if the input is aliased to an output and if it is
-               not dead after the instruction, we must allocate
-               a new register and move it */
-            goto allocate_in_reg;
+        if (arg_ct->ct & TCG_CT_IALIAS) {
+            if (ts->fixed_reg) {
+                /* if fixed register, we must allocate a new register
+                   if the alias is not the same register */
+                if (arg != args[arg_ct->alias_index])
+                    goto allocate_in_reg;
+            } else {
+                /* if the input is aliased to an output and if it is
+                   not dead after the instruction, we must allocate
+                   a new register and move it */
+                if (!IS_DEAD_IARG(i - nb_oargs)) 
+                    goto allocate_in_reg;
+            }
         }
         reg = ts->reg;
         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
@@ -1404,7 +1417,7 @@
         arg_ct = &def->args_ct[i];
         ts = &s->temps[arg];
         if (arg_ct->ct & TCG_CT_ALIAS) {
-            reg = new_args[arg_ct->ct & ~TCG_CT_ALIAS];
+            reg = new_args[arg_ct->alias_index];
         } else {
             /* if fixed register, we try to use it */
             reg = ts->reg;
@@ -1694,6 +1707,18 @@
         case INDEX_op_nopn:
             args += args[0];
             goto next;
+        case INDEX_op_discard:
+            {
+                TCGTemp *ts;
+                ts = &s->temps[args[0]];
+                /* mark the temporary as dead */
+                if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {
+                    if (ts->val_type == TEMP_VAL_REG)
+                        s->reg_to_temp[ts->reg] = -1;
+                    ts->val_type = TEMP_VAL_DEAD;
+                }
+            }
+            break;
         case INDEX_op_macro_goto:
             macro_op_index = op_index; /* only used for exceptions */
             op_index = args[0] - 1;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 231082e..11e9d8a 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -275,7 +275,8 @@
 #define TCG_CT_CONST  0x02 /* any constant of register size */
 
 typedef struct TCGArgConstraint {
-    uint32_t ct;
+    uint16_t ct;
+    uint8_t alias_index;
     union {
         TCGRegSet regs;
     } u;
@@ -286,6 +287,7 @@
 #define TCG_OPF_BB_END     0x01 /* instruction defines the end of a basic
                                    block */
 #define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers */
+#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects */
 
 typedef struct TCGOpDef {
     const char *name;