aboutsummaryrefslogtreecommitdiff
path: root/tcg
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2012-10-02 11:32:29 -0700
committerAurelien Jarno <aurelien@aurel32.net>2012-10-17 17:51:37 +0200
commit1305c451e67e3def030720013415103f5e0f5e11 (patch)
treeac3f3a855f82c2a844f5c1b15308dad6a7cc51d3 /tcg
parent212c328d615f6750659d39c6fd544d05be314fa1 (diff)
tcg: Optimize half-dead add2/sub2
When x86_64 guest is not in 64-bit mode, the high-part of the 64-bit add is dead. When the host is 32-bit, we can simplify to 32-bit arithmetic. Signed-off-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'tcg')
-rw-r--r--tcg/tcg.c34
1 files changed, 33 insertions, 1 deletions
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 32cd0c6b65..0eb407b723 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1307,8 +1307,39 @@ static void tcg_liveness_analysis(TCGContext *s)
break;
case INDEX_op_end:
break;
- /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
+
+ case INDEX_op_add2_i32:
+ case INDEX_op_sub2_i32:
+ args -= 6;
+ nb_iargs = 4;
+ nb_oargs = 2;
+ /* Test if the high part of the operation is dead, but not
+ the low part. The result can be optimized to a simple
+ add or sub. This happens often for x86_64 guest when the
+ cpu mode is set to 32 bit. */
+ if (dead_temps[args[1]]) {
+ if (dead_temps[args[0]]) {
+ goto do_remove;
+ }
+ /* Create the single operation plus nop. */
+ if (op == INDEX_op_add2_i32) {
+ op = INDEX_op_add_i32;
+ } else {
+ op = INDEX_op_sub_i32;
+ }
+ gen_opc_buf[op_index] = op;
+ args[1] = args[2];
+ args[2] = args[4];
+ assert(gen_opc_buf[op_index + 1] == INDEX_op_nop);
+ tcg_set_nop(s, gen_opc_buf + op_index + 1, args + 3, 3);
+ /* Fall through and mark the single-word operation live. */
+ nb_iargs = 2;
+ nb_oargs = 1;
+ }
+ goto do_not_remove;
+
default:
+ /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
args -= def->nb_args;
nb_iargs = def->nb_iargs;
nb_oargs = def->nb_oargs;
@@ -1322,6 +1353,7 @@ static void tcg_liveness_analysis(TCGContext *s)
if (!dead_temps[arg])
goto do_not_remove;
}
+ do_remove:
tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
#ifdef CONFIG_PROFILER
s->del_op_count++;