aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--TODO37
-rw-r--r--aio-posix.c130
-rw-r--r--async.c2
-rwxr-xr-xconfigure52
-rw-r--r--coroutine-sigaltstack.c26
-rw-r--r--coroutine-ucontext.c27
-rw-r--r--cpu-exec.c6
-rw-r--r--disas/i386.c9
-rw-r--r--disas/m68k.c11
-rw-r--r--hw/grlib_apbuart.c52
-rw-r--r--hw/qxl-render.c3
-rw-r--r--hw/usb/hcd-xhci.c4
-rw-r--r--hw/usb/redirect.c2
-rw-r--r--hw/vga.c18
-rw-r--r--hw/vmware_vga.c2
-rw-r--r--hw/xenfb.c3
-rw-r--r--include/block/aio.h3
-rw-r--r--include/exec/cpu-defs.h2
-rw-r--r--include/qemu/log.h8
-rw-r--r--include/qemu/main-loop.h4
-rw-r--r--include/sysemu/os-win32.h8
-rw-r--r--include/sysemu/sysemu.h1
-rw-r--r--include/ui/console.h13
-rw-r--r--iohandler.c40
-rw-r--r--main-loop.c158
-rw-r--r--monitor.c6
-rw-r--r--po/Makefile46
-rw-r--r--po/de_DE.po41
-rw-r--r--po/it.po41
-rw-r--r--po/messages.po41
-rw-r--r--qapi-schema.json6
-rw-r--r--qemu-char.c2
-rw-r--r--qemu-options.hx4
-rw-r--r--qom/object.c4
-rw-r--r--slirp/libslirp.h6
-rw-r--r--slirp/main.h1
-rw-r--r--slirp/slirp.c673
-rw-r--r--slirp/socket.c9
-rw-r--r--slirp/socket.h2
-rw-r--r--stubs/slirp.c6
-rw-r--r--target-alpha/helper.h1
-rw-r--r--target-alpha/int_helper.c7
-rw-r--r--target-alpha/translate.c20
-rw-r--r--target-arm/helper.c5
-rw-r--r--target-arm/helper.h5
-rw-r--r--target-arm/op_helper.c30
-rw-r--r--target-arm/translate.c137
-rw-r--r--target-cris/translate.c46
-rw-r--r--target-i386/cc_helper.c260
-rw-r--r--target-i386/cc_helper_template.h261
-rw-r--r--target-i386/cpu.c18
-rw-r--r--target-i386/cpu.h26
-rw-r--r--target-i386/helper.c13
-rw-r--r--target-i386/helper.h13
-rw-r--r--target-i386/int_helper.c69
-rw-r--r--target-i386/shift_helper_template.h12
-rw-r--r--target-i386/translate.c2635
-rw-r--r--target-lm32/translate.c2
-rw-r--r--target-microblaze/translate.c2
-rw-r--r--target-mips/dsp_helper.c4
-rw-r--r--target-mips/helper.h2
-rw-r--r--target-mips/op_helper.c12
-rw-r--r--target-mips/translate.c48
-rw-r--r--target-openrisc/translate.c2
-rw-r--r--target-ppc/cpu.h24
-rw-r--r--target-ppc/helper.h2
-rw-r--r--target-ppc/int_helper.c56
-rw-r--r--target-ppc/kvm.c4
-rw-r--r--target-ppc/machine.c8
-rw-r--r--target-ppc/translate.c677
-rw-r--r--target-ppc/translate_init.c4
-rw-r--r--target-s390x/helper.h1
-rw-r--r--target-s390x/int_helper.c8
-rw-r--r--target-s390x/translate.c3
-rw-r--r--target-sh4/translate.c30
-rw-r--r--target-sparc/cpu.c6
-rw-r--r--target-sparc/cpu.h1
-rw-r--r--target-sparc/helper.c11
-rw-r--r--target-sparc/helper.h1
-rw-r--r--target-sparc/ldst_helper.c6
-rw-r--r--target-sparc/translate.c92
-rw-r--r--target-unicore32/translate.c83
-rw-r--r--target-xtensa/translate.c49
-rw-r--r--tcg-runtime.c16
-rw-r--r--tcg/README30
-rw-r--r--tcg/arm/tcg-target.c4
-rw-r--r--tcg/arm/tcg-target.h1
-rw-r--r--tcg/hppa/tcg-target.h1
-rw-r--r--tcg/i386/tcg-target.c49
-rw-r--r--tcg/i386/tcg-target.h8
-rw-r--r--tcg/ia64/tcg-target.h8
-rw-r--r--tcg/mips/tcg-target.h1
-rw-r--r--tcg/optimize.c5
-rw-r--r--tcg/ppc/tcg-target.h1
-rw-r--r--tcg/ppc64/tcg-target.h8
-rw-r--r--tcg/s390/tcg-target.h8
-rw-r--r--tcg/sparc/tcg-target.c6
-rw-r--r--tcg/sparc/tcg-target.h8
-rw-r--r--tcg/tcg-op.h228
-rw-r--r--tcg/tcg-opc.h12
-rw-r--r--tcg/tcg-runtime.h2
-rw-r--r--tcg/tcg.c28
-rw-r--r--tcg/tcg.h10
-rw-r--r--tcg/tci/tcg-target.h9
-rw-r--r--tests/tcg/mips/mips32-dspr2/mulq_rs_w.c2
-rw-r--r--tests/tcg/mips/mips32-dspr2/mulq_s_ph.c15
-rw-r--r--tests/tcg/mips/mips32-dspr2/mulq_s_w.c2
-rw-r--r--tests/tcg/test-i386.c10
-rw-r--r--ui/Makefile.objs3
-rw-r--r--ui/console.c23
-rw-r--r--ui/gtk.c1217
-rw-r--r--user-exec.c2
-rw-r--r--vl.c48
114 files changed, 5014 insertions, 2959 deletions
diff --git a/Makefile b/Makefile
index 0d9099a473..2262410f0f 100644
--- a/Makefile
+++ b/Makefile
@@ -314,6 +314,9 @@ ifneq ($(BLOBS),)
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
done
endif
+ifeq ($(CONFIG_GTK),y)
+ $(MAKE) -C po $@
+endif
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
set -e; for x in $(KEYMAPS); do \
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
diff --git a/TODO b/TODO
deleted file mode 100644
index 1d4c638f27..0000000000
--- a/TODO
+++ /dev/null
@@ -1,37 +0,0 @@
-General:
--------
-- cycle counter for all archs
-- cpu_interrupt() win32/SMP fix
-- merge PIC spurious interrupt patch
-- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
-- config file (at least for windows/Mac OS X)
-- update doc: PCI infos.
-- basic VGA optimizations
-- better code fetch
-- do not resize vga if invalid size.
-- TLB code protection support for PPC
-- disable SMC handling for ARM/SPARC/PPC (not finished)
-- see undefined flags for BTx insn
-- keyboard output buffer filling timing emulation
-- tests for each target CPU
-- fix all remaining thread lock issues (must put TBs in a specific invalid
- state, find a solution for tb_flush()).
-
-ppc specific:
-------------
-- TLB invalidate not needed if msr_pr changes
-- enable shift optimizations ?
-
-linux-user specific:
--------------------
-- remove threading support as it cannot work at this point
-- improve IPC syscalls
-- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
- issues, fix 16 bit uid issues)
-- use kernel traps for unaligned accesses on ARM ?
-
-
-lower priority:
---------------
-- int15 ah=86: use better timing
-- use -msoft-float on ARM
diff --git a/aio-posix.c b/aio-posix.c
index fe4dbb4523..b68eccd40c 100644
--- a/aio-posix.c
+++ b/aio-posix.c
@@ -25,6 +25,7 @@ struct AioHandler
IOHandler *io_write;
AioFlushHandler *io_flush;
int deleted;
+ int pollfds_idx;
void *opaque;
QLIST_ENTRY(AioHandler) node;
};
@@ -85,9 +86,10 @@ void aio_set_fd_handler(AioContext *ctx,
node->io_write = io_write;
node->io_flush = io_flush;
node->opaque = opaque;
+ node->pollfds_idx = -1;
- node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0);
- node->pfd.events |= (io_write ? G_IO_OUT : 0);
+ node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
+ node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
}
aio_notify(ctx);
@@ -110,13 +112,6 @@ bool aio_pending(AioContext *ctx)
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
int revents;
- /*
- * FIXME: right now we cannot get G_IO_HUP and G_IO_ERR because
- * main-loop.c is still select based (due to the slirp legacy).
- * If main-loop.c ever switches to poll, G_IO_ERR should be
- * tested too. Dispatching G_IO_ERR to both handlers should be
- * okay, since handlers need to be ready for spurious wakeups.
- */
revents = node->pfd.revents & node->pfd.events;
if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
return true;
@@ -129,30 +124,12 @@ bool aio_pending(AioContext *ctx)
return false;
}
-bool aio_poll(AioContext *ctx, bool blocking)
+static bool aio_dispatch(AioContext *ctx)
{
- static struct timeval tv0;
AioHandler *node;
- fd_set rdfds, wrfds;
- int max_fd = -1;
- int ret;
- bool busy, progress;
-
- progress = false;
-
- /*
- * If there are callbacks left that have been queued, we need to call then.
- * Do not call select in this case, because it is possible that the caller
- * does not need a complete flush (as is the case for qemu_aio_wait loops).
- */
- if (aio_bh_poll(ctx)) {
- blocking = false;
- progress = true;
- }
+ bool progress = false;
/*
- * Then dispatch any pending callbacks from the GSource.
- *
* We have to walk very carefully in case qemu_aio_set_fd_handler is
* called while we're walking.
*/
@@ -166,12 +143,15 @@ bool aio_poll(AioContext *ctx, bool blocking)
revents = node->pfd.revents & node->pfd.events;
node->pfd.revents = 0;
- /* See comment in aio_pending. */
- if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
+ if (!node->deleted &&
+ (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
+ node->io_read) {
node->io_read(node->opaque);
progress = true;
}
- if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
+ if (!node->deleted &&
+ (revents & (G_IO_OUT | G_IO_ERR)) &&
+ node->io_write) {
node->io_write(node->opaque);
progress = true;
}
@@ -186,6 +166,30 @@ bool aio_poll(AioContext *ctx, bool blocking)
g_free(tmp);
}
}
+ return progress;
+}
+
+bool aio_poll(AioContext *ctx, bool blocking)
+{
+ AioHandler *node;
+ int ret;
+ bool busy, progress;
+
+ progress = false;
+
+ /*
+ * If there are callbacks left that have been queued, we need to call them.
+ * Do not call select in this case, because it is possible that the caller
+ * does not need a complete flush (as is the case for qemu_aio_wait loops).
+ */
+ if (aio_bh_poll(ctx)) {
+ blocking = false;
+ progress = true;
+ }
+
+ if (aio_dispatch(ctx)) {
+ progress = true;
+ }
if (progress && !blocking) {
return true;
@@ -193,12 +197,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
ctx->walking_handlers++;
- FD_ZERO(&rdfds);
- FD_ZERO(&wrfds);
+ g_array_set_size(ctx->pollfds, 0);
- /* fill fd sets */
+ /* fill pollfds */
busy = false;
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+ node->pollfds_idx = -1;
+
/* If there aren't pending AIO operations, don't invoke callbacks.
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
* wait indefinitely.
@@ -209,13 +214,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
}
busy = true;
}
- if (!node->deleted && node->io_read) {
- FD_SET(node->pfd.fd, &rdfds);
- max_fd = MAX(max_fd, node->pfd.fd + 1);
- }
- if (!node->deleted && node->io_write) {
- FD_SET(node->pfd.fd, &wrfds);
- max_fd = MAX(max_fd, node->pfd.fd + 1);
+ if (!node->deleted && node->pfd.events) {
+ GPollFD pfd = {
+ .fd = node->pfd.fd,
+ .events = node->pfd.events,
+ };
+ node->pollfds_idx = ctx->pollfds->len;
+ g_array_append_val(ctx->pollfds, pfd);
}
}
@@ -227,41 +232,22 @@ bool aio_poll(AioContext *ctx, bool blocking)
}
/* wait until next event */
- ret = select(max_fd, &rdfds, &wrfds, NULL, blocking ? NULL : &tv0);
+ ret = g_poll((GPollFD *)ctx->pollfds->data,
+ ctx->pollfds->len,
+ blocking ? -1 : 0);
/* if we have any readable fds, dispatch event */
if (ret > 0) {
- /* we have to walk very carefully in case
- * qemu_aio_set_fd_handler is called while we're walking */
- node = QLIST_FIRST(&ctx->aio_handlers);
- while (node) {
- AioHandler *tmp;
-
- ctx->walking_handlers++;
-
- if (!node->deleted &&
- FD_ISSET(node->pfd.fd, &rdfds) &&
- node->io_read) {
- node->io_read(node->opaque);
- progress = true;
- }
- if (!node->deleted &&
- FD_ISSET(node->pfd.fd, &wrfds) &&
- node->io_write) {
- node->io_write(node->opaque);
- progress = true;
- }
-
- tmp = node;
- node = QLIST_NEXT(node, node);
-
- ctx->walking_handlers--;
-
- if (!ctx->walking_handlers && tmp->deleted) {
- QLIST_REMOVE(tmp, node);
- g_free(tmp);
+ QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+ if (node->pollfds_idx != -1) {
+ GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
+ node->pollfds_idx);
+ node->pfd.revents = pfd->revents;
}
}
+ if (aio_dispatch(ctx)) {
+ progress = true;
+ }
}
assert(progress || busy);
diff --git a/async.c b/async.c
index 72d268ae35..f2d47ba96d 100644
--- a/async.c
+++ b/async.c
@@ -174,6 +174,7 @@ aio_ctx_finalize(GSource *source)
aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
event_notifier_cleanup(&ctx->notifier);
+ g_array_free(ctx->pollfds, TRUE);
}
static GSourceFuncs aio_source_funcs = {
@@ -198,6 +199,7 @@ AioContext *aio_context_new(void)
{
AioContext *ctx;
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
+ ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
event_notifier_init(&ctx->notifier, false);
aio_set_event_notifier(ctx, &ctx->notifier,
(EventNotifierHandler *)
diff --git a/configure b/configure
index 42cb3144a5..dcaa67c6d3 100755
--- a/configure
+++ b/configure
@@ -226,6 +226,7 @@ coroutine=""
seccomp=""
glusterfs=""
virtio_blk_data_plane=""
+gtk=""
# parse CC options first
for opt do
@@ -897,6 +898,10 @@ for opt do
;;
--enable-virtio-blk-data-plane) virtio_blk_data_plane="yes"
;;
+ --disable-gtk) gtk="no"
+ ;;
+ --enable-gtk) gtk="yes"
+ ;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@@ -1636,6 +1641,26 @@ if test "$sparse" != "no" ; then
fi
##########################################
+# GTK probe
+
+if test "$gtk" != "no"; then
+ if $pkg_config --exists 'gtk+-2.0 >= 2.18.0' && \
+ $pkg_config --exists 'vte >= 0.24.0'; then
+ gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null`
+ gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null`
+ vte_cflags=`$pkg_config --cflags vte 2>/dev/null`
+ vte_libs=`$pkg_config --libs vte 2>/dev/null`
+ libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
+ gtk="yes"
+ else
+ if test "$gtk" = "yes" ; then
+ feature_not_found "gtk"
+ fi
+ gtk="no"
+ fi
+fi
+
+##########################################
# SDL probe
# Look for sdl configuration program (pkg-config or sdl-config). Try
@@ -3090,20 +3115,27 @@ if compile_prog "" "" ; then
fi
########################################
-# check whether we can disable the -Wunused-but-set-variable
-# option with a pragma (this is needed to silence a warning in
-# some versions of the valgrind VALGRIND_STACK_DEREGISTER macro.)
-# This test has to be compiled with -Werror as otherwise an
-# unknown pragma is only a warning.
+# check whether we can disable warning option with a pragma (this is needed
+# to silence warnings in the headers of some versions of external libraries).
+# This test has to be compiled with -Werror as otherwise an unknown pragma is
+# only a warning.
+#
+# If we can't selectively disable warning in the code, disable -Werror so that
+# the build doesn't fail anyway.
+
pragma_disable_unused_but_set=no
cat > $TMPC << EOF
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+
int main(void) {
return 0;
}
EOF
if compile_prog "-Werror" "" ; then
pragma_diagnostic_available=yes
+else
+ werror=no
fi
########################################
@@ -3218,6 +3250,7 @@ fi
qemu_confdir=$sysconfdir$confsuffix
qemu_datadir=$datadir$confsuffix
+qemu_localedir="$datadir/locale"
tools=""
if test "$want_tools" = "yes" ; then
@@ -3301,6 +3334,7 @@ if test "$darwin" = "yes" ; then
fi
echo "pixman $pixman"
echo "SDL support $sdl"
+echo "GTK support $gtk"
echo "curses support $curses"
echo "curl support $curl"
echo "mingw32 support $mingw32"
@@ -3390,6 +3424,7 @@ echo "qemu_localstatedir=$local_statedir" >> $config_host_mak
echo "qemu_helperdir=$libexecdir" >> $config_host_mak
echo "extra_cflags=$EXTRA_CFLAGS" >> $config_host_mak
echo "extra_ldflags=$EXTRA_LDFLAGS" >> $config_host_mak
+echo "qemu_localedir=$qemu_localedir" >> $config_host_mak
echo "ARCH=$ARCH" >> $config_host_mak
if test "$debug_tcg" = "yes" ; then
@@ -3591,6 +3626,11 @@ if test "$bluez" = "yes" ; then
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
fi
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
+if test "$gtk" = "yes" ; then
+ echo "CONFIG_GTK=y" >> $config_host_mak
+ echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
+ echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
+fi
if test "$xen" = "yes" ; then
echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
@@ -4305,7 +4345,7 @@ DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS qapi-generated"
FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
-FILES="$FILES tests/tcg/lm32/Makefile"
+FILES="$FILES tests/tcg/lm32/Makefile po/Makefile"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
FILES="$FILES pc-bios/spapr-rtas/Makefile"
FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
diff --git a/coroutine-sigaltstack.c b/coroutine-sigaltstack.c
index e37ebac9c4..1fb41c9f14 100644
--- a/coroutine-sigaltstack.c
+++ b/coroutine-sigaltstack.c
@@ -45,7 +45,7 @@ static unsigned int pool_size;
typedef struct {
Coroutine base;
void *stack;
- jmp_buf env;
+ sigjmp_buf env;
} CoroutineUContext;
/**
@@ -59,7 +59,7 @@ typedef struct {
CoroutineUContext leader;
/** Information for the signal handler (trampoline) */
- jmp_buf tr_reenter;
+ sigjmp_buf tr_reenter;
volatile sig_atomic_t tr_called;
void *tr_handler;
} CoroutineThreadState;
@@ -115,8 +115,8 @@ static void __attribute__((constructor)) coroutine_init(void)
static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co)
{
/* Initialize longjmp environment and switch back the caller */
- if (!setjmp(self->env)) {
- longjmp(*(jmp_buf *)co->entry_arg, 1);
+ if (!sigsetjmp(self->env, 0)) {
+ siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
}
while (true) {
@@ -145,14 +145,14 @@ static void coroutine_trampoline(int signal)
/*
* Here we have to do a bit of a ping pong between the caller, given that
* this is a signal handler and we have to do a return "soon". Then the
- * caller can reestablish everything and do a longjmp here again.
+ * caller can reestablish everything and do a siglongjmp here again.
*/
- if (!setjmp(coTS->tr_reenter)) {
+ if (!sigsetjmp(coTS->tr_reenter, 0)) {
return;
}
/*
- * Ok, the caller has longjmp'ed back to us, so now prepare
+ * Ok, the caller has siglongjmp'ed back to us, so now prepare
* us for the real machine state switching. We have to jump
* into another function here to get a new stack context for
* the auto variables (which have to be auto-variables
@@ -179,7 +179,7 @@ static Coroutine *coroutine_new(void)
/* The way to manipulate stack is with the sigaltstack function. We
* prepare a stack, with it delivering a signal to ourselves and then
- * put setjmp/longjmp where needed.
+ * put sigsetjmp/siglongjmp where needed.
* This has been done keeping coroutine-ucontext as a model and with the
* pth ideas (GNU Portable Threads). See coroutine-ucontext for the basics
* of the coroutines and see pth_mctx.c (from the pth project) for the
@@ -220,7 +220,7 @@ static Coroutine *coroutine_new(void)
/*
* Now transfer control onto the signal stack and set it up.
- * It will return immediately via "return" after the setjmp()
+ * It will return immediately via "return" after the sigsetjmp()
* was performed. Be careful here with race conditions. The
* signal can be delivered the first time sigsuspend() is
* called.
@@ -261,8 +261,8 @@ static Coroutine *coroutine_new(void)
* type-conversion warnings related to the `volatile' qualifier and
* the fact that `jmp_buf' usually is an array type.
*/
- if (!setjmp(old_env)) {
- longjmp(coTS->tr_reenter, 1);
+ if (!sigsetjmp(old_env, 0)) {
+ siglongjmp(coTS->tr_reenter, 1);
}
/*
@@ -311,9 +311,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
s->current = to_;
- ret = setjmp(from->env);
+ ret = sigsetjmp(from->env, 0);
if (ret == 0) {
- longjmp(to->env, action);
+ siglongjmp(to->env, action);
}
return ret;
}
diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c
index a9c30e9df4..bd20e384b7 100644
--- a/coroutine-ucontext.c
+++ b/coroutine-ucontext.c
@@ -46,7 +46,7 @@ static unsigned int pool_size;
typedef struct {
Coroutine base;
void *stack;
- jmp_buf env;
+ sigjmp_buf env;
#ifdef CONFIG_VALGRIND_H
unsigned int valgrind_stack_id;
@@ -130,8 +130,8 @@ static void coroutine_trampoline(int i0, int i1)
co = &self->base;
/* Initialize longjmp environment and switch back the caller */
- if (!setjmp(self->env)) {
- longjmp(*(jmp_buf *)co->entry_arg, 1);
+ if (!sigsetjmp(self->env, 0)) {
+ siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
}
while (true) {
@@ -145,14 +145,15 @@ static Coroutine *coroutine_new(void)
const size_t stack_size = 1 << 20;
CoroutineUContext *co;
ucontext_t old_uc, uc;
- jmp_buf old_env;
+ sigjmp_buf old_env;
union cc_arg arg = {0};
- /* The ucontext functions preserve signal masks which incurs a system call
- * overhead. setjmp()/longjmp() does not preserve signal masks but only
- * works on the current stack. Since we need a way to create and switch to
- * a new stack, use the ucontext functions for that but setjmp()/longjmp()
- * for everything else.
+ /* The ucontext functions preserve signal masks which incurs a
+ * system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not
+ * preserve signal masks but only works on the current stack.
+ * Since we need a way to create and switch to a new stack, use
+ * the ucontext functions for that but sigsetjmp()/siglongjmp() for
+ * everything else.
*/
if (getcontext(&uc) == -1) {
@@ -178,8 +179,8 @@ static Coroutine *coroutine_new(void)
makecontext(&uc, (void (*)(void))coroutine_trampoline,
2, arg.i[0], arg.i[1]);
- /* swapcontext() in, longjmp() back out */
- if (!setjmp(old_env)) {
+ /* swapcontext() in, siglongjmp() back out */
+ if (!sigsetjmp(old_env, 0)) {
swapcontext(&old_uc, &uc);
}
return &co->base;
@@ -242,9 +243,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
s->current = to_;
- ret = setjmp(from->env);
+ ret = sigsetjmp(from->env, 0);
if (ret == 0) {
- longjmp(to->env, action);
+ siglongjmp(to->env, action);
}
return ret;
}
diff --git a/cpu-exec.c b/cpu-exec.c
index 9fcfe9e0db..afbe4977ab 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -35,7 +35,7 @@ void cpu_loop_exit(CPUArchState *env)
CPUState *cpu = ENV_GET_CPU(env);
cpu->current_tb = NULL;
- longjmp(env->jmp_env, 1);
+ siglongjmp(env->jmp_env, 1);
}
/* exit the current TB from a signal handler. The host registers are
@@ -47,7 +47,7 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc)
/* XXX: restore cpu registers saved in host registers */
env->exception_index = -1;
- longjmp(env->jmp_env, 1);
+ siglongjmp(env->jmp_env, 1);
}
#endif
@@ -234,7 +234,7 @@ int cpu_exec(CPUArchState *env)
/* prepare setjmp context for exception handling */
for(;;) {
- if (setjmp(env->jmp_env) == 0) {
+ if (sigsetjmp(env->jmp_env, 0) == 0) {
/* if an exception is pending, we execute it here */
if (env->exception_index >= 0) {
if (env->exception_index >= EXCP_INTERRUPT) {
diff --git a/disas/i386.c b/disas/i386.c
index 3b006b13e0..73cc06f1c3 100644
--- a/disas/i386.c
+++ b/disas/i386.c
@@ -226,7 +226,7 @@ struct dis_private {
bfd_byte the_buffer[MAX_MNEM_SIZE];
bfd_vma insn_start;
int orig_sizeflag;
- jmp_buf bailout;
+ sigjmp_buf bailout;
};
enum address_mode
@@ -303,7 +303,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr)
STATUS. */
if (priv->max_fetched == priv->the_buffer)
(*info->memory_error_func) (status, start, info);
- longjmp (priv->bailout, 1);
+ siglongjmp(priv->bailout, 1);
}
else
priv->max_fetched = addr;
@@ -3661,7 +3661,7 @@ print_insn (bfd_vma pc, disassemble_info *info)
start_codep = priv.the_buffer;
codep = priv.the_buffer;
- if (setjmp (priv.bailout) != 0)
+ if (sigsetjmp(priv.bailout, 0) != 0)
{
const char *name;
@@ -4720,7 +4720,8 @@ print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp)
buf[0] = '0';
buf[1] = 'x';
snprintf_vma (tmp, sizeof(tmp), disp);
- for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++);
+ for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++) {
+ }
pstrcpy (buf + 2, bufsize - 2, tmp + i);
}
else
diff --git a/disas/m68k.c b/disas/m68k.c
index c950241f79..cc0db96cae 100644
--- a/disas/m68k.c
+++ b/disas/m68k.c
@@ -624,7 +624,7 @@ struct private
bfd_byte *max_fetched;
bfd_byte the_buffer[MAXLEN];
bfd_vma insn_start;
- jmp_buf bailout;
+ sigjmp_buf bailout;
};
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
@@ -644,7 +644,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr)
if (status != 0)
{
(*info->memory_error_func) (status, start, info);
- longjmp (priv->bailout, 1);
+ siglongjmp(priv->bailout, 1);
}
else
priv->max_fetched = addr;
@@ -1912,9 +1912,10 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
priv.max_fetched = priv.the_buffer;
priv.insn_start = memaddr;
- if (setjmp (priv.bailout) != 0)
- /* Error return. */
- return -1;
+ if (sigsetjmp(priv.bailout, 0) != 0) {
+ /* Error return. */
+ return -1;
+ }
switch (info->mach)
{
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index 760bed0b72..ba1685afd1 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -75,7 +75,6 @@ typedef struct UART {
CharDriverState *chr;
/* registers */
- uint32_t receive;
uint32_t status;
uint32_t control;
@@ -136,12 +135,14 @@ static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
{
UART *uart = opaque;
- uart_add_to_fifo(uart, buf, size);
+ if (uart->control & UART_RECEIVE_ENABLE) {
+ uart_add_to_fifo(uart, buf, size);
- uart->status |= UART_DATA_READY;
+ uart->status |= UART_DATA_READY;
- if (uart->control & UART_RECEIVE_INTERRUPT) {
- qemu_irq_pulse(uart->irq);
+ if (uart->control & UART_RECEIVE_INTERRUPT) {
+ qemu_irq_pulse(uart->irq);
+ }
}
}
@@ -193,8 +194,15 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr,
switch (addr) {
case DATA_OFFSET:
case DATA_OFFSET + 3: /* When only one byte write */
- c = value & 0xFF;
- qemu_chr_fe_write(uart->chr, &c, 1);
+ /* Transmit when character device available and transmitter enabled */
+ if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {
+ c = value & 0xFF;
+ qemu_chr_fe_write(uart->chr, &c, 1);
+ /* Generate interrupt */
+ if (uart->control & UART_TRANSMIT_INTERRUPT) {
+ qemu_irq_pulse(uart->irq);
+ }
+ }
return;
case STATUS_OFFSET:
@@ -242,30 +250,44 @@ static int grlib_apbuart_init(SysBusDevice *dev)
return 0;
}
-static Property grlib_gptimer_properties[] = {
+static void grlib_apbuart_reset(DeviceState *d)
+{
+ UART *uart = container_of(d, UART, busdev.qdev);
+
+ /* Transmitter FIFO and shift registers are always empty in QEMU */
+ uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
+ /* Everything is off */
+ uart->control = 0;
+ /* Flush receive FIFO */
+ uart->len = 0;
+ uart->current = 0;
+}
+
+static Property grlib_apbuart_properties[] = {
DEFINE_PROP_CHR("chrdev", UART, chr),
DEFINE_PROP_END_OF_LIST(),
};
-static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
k->init = grlib_apbuart_init;
- dc->props = grlib_gptimer_properties;
+ dc->reset = grlib_apbuart_reset;
+ dc->props = grlib_apbuart_properties;
}
-static const TypeInfo grlib_gptimer_info = {
+static const TypeInfo grlib_apbuart_info = {
.name = "grlib,apbuart",
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(UART),
- .class_init = grlib_gptimer_class_init,
+ .class_init = grlib_apbuart_class_init,
};
-static void grlib_gptimer_register_types(void)
+static void grlib_apbuart_register_types(void)
{
- type_register_static(&grlib_gptimer_info);
+ type_register_static(&grlib_apbuart_info);
}
-type_init(grlib_gptimer_register_types)
+type_init(grlib_apbuart_register_types)
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 88e63f8085..455fb91269 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -118,7 +118,8 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
qxl->guest_primary.surface.height,
qxl->guest_primary.bits_pp,
qxl->guest_primary.abs_stride,
- qxl->guest_primary.data);
+ qxl->guest_primary.data,
+ false);
} else {
qemu_resize_displaysurface(vga->ds,
qxl->guest_primary.surface.width,
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 5796102f3a..07afdeef5b 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1152,8 +1152,8 @@ static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
if (sctx->sct == -1) {
xhci_dma_read_u32s(epctx->xhci, sctx->pctx, ctx, sizeof(ctx));
- fprintf(stderr, "%s: init sctx #%d @ %lx: %08x %08x\n", __func__,
- streamid, sctx->pctx, ctx[0], ctx[1]);
+ fprintf(stderr, "%s: init sctx #%d @ " DMA_ADDR_FMT ": %08x %08x\n",
+ __func__, streamid, sctx->pctx, ctx[0], ctx[1]);
sct = (ctx[0] >> 1) & 0x07;
if (epctx->lsa && sct != 1) {
*cc_error = CC_INVALID_STREAM_TYPE_ERROR;
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 7078403904..c519b9b92a 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1897,7 +1897,7 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
}
if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
- usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f));
+ usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0);
}
/* bufp_alloc also adds the packet to the ep queue */
diff --git a/hw/vga.c b/hw/vga.c
index e2ba7f208c..1caf23d7b6 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1643,6 +1643,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
uint8_t *d;
uint32_t v, addr1, addr;
vga_draw_line_func *vga_draw_line;
+#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+ static const bool byteswap = false;
+#else
+ static const bool byteswap = true;
+#endif
full_update |= update_basic_params(s);
@@ -1685,18 +1690,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
disp_width != s->last_width ||
height != s->last_height ||
s->last_depth != depth) {
-#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
- if (depth == 16 || depth == 32) {
-#else
- if (depth == 32) {
-#endif
+ if (depth == 32 || (depth == 16 && !byteswap)) {
qemu_free_displaysurface(s->ds);
s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
s->line_offset,
- s->vram_ptr + (s->start_addr * 4));
-#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
- s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
-#endif
+ s->vram_ptr + (s->start_addr * 4), byteswap);
dpy_gfx_resize(s->ds);
} else {
qemu_console_resize(s->ds, disp_width, height);
@@ -1715,7 +1713,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
s->ds->surface = qemu_create_displaysurface_from(disp_width,
height, depth,
s->line_offset,
- s->vram_ptr + (s->start_addr * 4));
+ s->vram_ptr + (s->start_addr * 4), byteswap);
dpy_gfx_setdata(s->ds);
}
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index cd15ee40a8..8fc201bfb9 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1074,7 +1074,7 @@ static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch,
ds_get_height(s->vga.ds),
32,
ds_get_linesize(s->vga.ds),
- s->vga.vram_ptr);
+ s->vga.vram_ptr, false);
ppm_save(filename, ds, errp);
g_free(ds);
}
diff --git a/hw/xenfb.c b/hw/xenfb.c
index 903efd3073..7f1f6b4643 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -756,7 +756,8 @@ static void xenfb_update(void *opaque)
qemu_free_displaysurface(xenfb->c.ds);
xenfb->c.ds->surface = qemu_create_displaysurface_from
(xenfb->width, xenfb->height, xenfb->depth,
- xenfb->row_stride, xenfb->pixels + xenfb->offset);
+ xenfb->row_stride, xenfb->pixels + xenfb->offset,
+ false);
break;
default:
/* we must convert stuff */
diff --git a/include/block/aio.h b/include/block/aio.h
index 8eda924599..5b54d383fc 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -63,6 +63,9 @@ typedef struct AioContext {
/* Used for aio_notify. */
EventNotifier notifier;
+
+ /* GPollFDs for aio_poll() */
+ GArray *pollfds;
} AioContext;
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index ae64590cdf..3dc96568ac 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -184,7 +184,7 @@ typedef struct CPUWatchpoint {
struct GDBRegisterState *gdb_regs; \
\
/* Core interrupt code */ \
- jmp_buf jmp_env; \
+ sigjmp_buf jmp_env; \
int exception_index; \
\
CPUArchState *next_cpu; /* next CPU sharing TB cache */ \
diff --git a/include/qemu/log.h b/include/qemu/log.h
index 5a46555112..452700329e 100644
--- a/include/qemu/log.h
+++ b/include/qemu/log.h
@@ -126,14 +126,6 @@ static inline void qemu_log_set_file(FILE *f)
qemu_logfile = f;
}
-/* Set up a new log file, only if none is set */
-static inline void qemu_log_try_set_file(FILE *f)
-{
- if (!qemu_logfile) {
- qemu_logfile = f;
- }
-}
-
/* define log items */
typedef struct QEMULogItem {
int mask;
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index e8059c3d0a..09952885a9 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -297,8 +297,8 @@ void qemu_mutex_unlock_iothread(void);
/* internal interfaces */
void qemu_fd_register(int fd);
-void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
-void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
+void qemu_iohandler_fill(GArray *pollfds);
+void qemu_iohandler_poll(GArray *pollfds, int rc);
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
void qemu_bh_schedule_idle(QEMUBH *bh);
diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h
index bf9edeb9ab..71f5fa0a91 100644
--- a/include/sysemu/os-win32.h
+++ b/include/sysemu/os-win32.h
@@ -63,6 +63,14 @@
# undef setjmp
# define setjmp(env) _setjmp(env, NULL)
#endif
+/* QEMU uses sigsetjmp()/siglongjmp() as the portable way to specify
+ * "longjmp and don't touch the signal masks". Since we know that the
+ * savemask parameter will always be zero we can safely define these
+ * in terms of setjmp/longjmp on Win32.
+ */
+#define sigjmp_buf jmp_buf
+#define sigsetjmp(env, savemask) setjmp(env)
+#define siglongjmp(env, val) longjmp(env, val)
/* Declaration of ffs() is missing in MinGW's strings.h. */
int ffs(int i);
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index ae49088d42..b19ec952b4 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -89,6 +89,7 @@ typedef enum DisplayType
DT_DEFAULT,
DT_CURSES,
DT_SDL,
+ DT_GTK,
DT_NOGRAPHIC,
DT_NONE,
} DisplayType;
diff --git a/include/ui/console.h b/include/ui/console.h
index fc23baa06b..c42bca6efe 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -184,7 +184,8 @@ struct DisplayState {
void register_displaystate(DisplayState *ds);
DisplayState *get_displaystate(void);
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
- int linesize, uint8_t *data);
+ int linesize, uint8_t *data,
+ bool byteswap);
PixelFormat qemu_different_endianness_pixelformat(int bpp);
PixelFormat qemu_default_pixelformat(int bpp);
@@ -442,7 +443,6 @@ void vga_hw_text_update(console_ch_t *chardata);
int is_graphic_console(void);
int is_fixedsize_console(void);
-CharDriverState *text_console_init(QemuOpts *opts);
void text_consoles_set_display(DisplayState *ds);
void console_select(unsigned int index);
void console_color_init(DisplayState *ds);
@@ -450,6 +450,11 @@ void qemu_console_resize(DisplayState *ds, int width, int height);
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
int dst_x, int dst_y, int w, int h);
+typedef CharDriverState *(VcHandler)(QemuOpts *);
+
+CharDriverState *vc_init(QemuOpts *opts);
+void register_vc_handler(VcHandler *handler);
+
/* sdl.c */
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
@@ -482,4 +487,8 @@ void curses_display_init(DisplayState *ds, int full_screen);
int index_from_key(const char *key);
int index_from_keycode(int code);
+/* gtk.c */
+void early_gtk_display_init(void);
+void gtk_display_init(DisplayState *ds);
+
#endif
diff --git a/iohandler.c b/iohandler.c
index 2523adc11d..ae2ef8f966 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -39,6 +39,7 @@ typedef struct IOHandlerRecord {
void *opaque;
QLIST_ENTRY(IOHandlerRecord) next;
int fd;
+ int pollfds_idx;
bool deleted;
} IOHandlerRecord;
@@ -78,6 +79,7 @@ int qemu_set_fd_handler2(int fd,
ioh->fd_read = fd_read;
ioh->fd_write = fd_write;
ioh->opaque = opaque;
+ ioh->pollfds_idx = -1;
ioh->deleted = 0;
qemu_notify_event();
}
@@ -92,38 +94,56 @@ int qemu_set_fd_handler(int fd,
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
}
-void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds)
+void qemu_iohandler_fill(GArray *pollfds)
{
IOHandlerRecord *ioh;
QLIST_FOREACH(ioh, &io_handlers, next) {
+ int events = 0;
+
if (ioh->deleted)
continue;
if (ioh->fd_read &&
(!ioh->fd_read_poll ||
ioh->fd_read_poll(ioh->opaque) != 0)) {
- FD_SET(ioh->fd, readfds);
- if (ioh->fd > *pnfds)
- *pnfds = ioh->fd;
+ events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
}
if (ioh->fd_write) {
- FD_SET(ioh->fd, writefds);
- if (ioh->fd > *pnfds)
- *pnfds = ioh->fd;
+ events |= G_IO_OUT | G_IO_ERR;
+ }
+ if (events) {
+ GPollFD pfd = {
+ .fd = ioh->fd,
+ .events = events,
+ };
+ ioh->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
+ } else {
+ ioh->pollfds_idx = -1;
}
}
}
-void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int ret)
+void qemu_iohandler_poll(GArray *pollfds, int ret)
{
if (ret > 0) {
IOHandlerRecord *pioh, *ioh;
QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
- if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, readfds)) {
+ int revents = 0;
+
+ if (!ioh->deleted && ioh->pollfds_idx != -1) {
+ GPollFD *pfd = &g_array_index(pollfds, GPollFD,
+ ioh->pollfds_idx);
+ revents = pfd->revents;
+ }
+
+ if (!ioh->deleted && ioh->fd_read &&
+ (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
ioh->fd_read(ioh->opaque);
}
- if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, writefds)) {
+ if (!ioh->deleted && ioh->fd_write &&
+ (revents & (G_IO_OUT | G_IO_ERR))) {
ioh->fd_write(ioh->opaque);
}
diff --git a/main-loop.c b/main-loop.c
index 6f52ac39bc..8c9b58c14c 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -117,6 +117,8 @@ void qemu_notify_event(void)
aio_notify(qemu_aio_context);
}
+static GArray *gpollfds;
+
int qemu_init_main_loop(void)
{
int ret;
@@ -133,6 +135,7 @@ int qemu_init_main_loop(void)
return ret;
}
+ gpollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
qemu_aio_context = aio_context_new();
src = aio_get_g_source(qemu_aio_context);
g_source_attach(src, NULL);
@@ -140,100 +143,63 @@ int qemu_init_main_loop(void)
return 0;
}
-static fd_set rfds, wfds, xfds;
-static int nfds;
-static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
-static int n_poll_fds;
static int max_priority;
#ifndef _WIN32
-static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
- fd_set *xfds, uint32_t *cur_timeout)
+static int glib_pollfds_idx;
+static int glib_n_poll_fds;
+
+static void glib_pollfds_fill(uint32_t *cur_timeout)
{
GMainContext *context = g_main_context_default();
- int i;
int timeout = 0;
+ int n;
g_main_context_prepare(context, &max_priority);
- n_poll_fds = g_main_context_query(context, max_priority, &timeout,
- poll_fds, ARRAY_SIZE(poll_fds));
- g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
-
- for (i = 0; i < n_poll_fds; i++) {
- GPollFD *p = &poll_fds[i];
-
- if ((p->events & G_IO_IN)) {
- FD_SET(p->fd, rfds);
- *max_fd = MAX(*max_fd, p->fd);
- }
- if ((p->events & G_IO_OUT)) {
- FD_SET(p->fd, wfds);
- *max_fd = MAX(*max_fd, p->fd);
- }
- if ((p->events & G_IO_ERR)) {
- FD_SET(p->fd, xfds);
- *max_fd = MAX(*max_fd, p->fd);
- }
- }
+ glib_pollfds_idx = gpollfds->len;
+ n = glib_n_poll_fds;
+ do {
+ GPollFD *pfds;
+ glib_n_poll_fds = n;
+ g_array_set_size(gpollfds, glib_pollfds_idx + glib_n_poll_fds);
+ pfds = &g_array_index(gpollfds, GPollFD, glib_pollfds_idx);
+ n = g_main_context_query(context, max_priority, &timeout, pfds,
+ glib_n_poll_fds);
+ } while (n != glib_n_poll_fds);
if (timeout >= 0 && timeout < *cur_timeout) {
*cur_timeout = timeout;
}
}
-static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
- bool err)
+static void glib_pollfds_poll(void)
{
GMainContext *context = g_main_context_default();
+ GPollFD *pfds = &g_array_index(gpollfds, GPollFD, glib_pollfds_idx);
- if (!err) {
- int i;
-
- for (i = 0; i < n_poll_fds; i++) {
- GPollFD *p = &poll_fds[i];
-
- if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) {
- p->revents |= G_IO_IN;
- }
- if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) {
- p->revents |= G_IO_OUT;
- }
- if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) {
- p->revents |= G_IO_ERR;
- }
- }
- }
-
- if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
+ if (g_main_context_check(context, max_priority, pfds, glib_n_poll_fds)) {
g_main_context_dispatch(context);
}
}
static int os_host_main_loop_wait(uint32_t timeout)
{
- struct timeval tv, *tvarg = NULL;
int ret;
- glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
-
- if (timeout < UINT32_MAX) {
- tvarg = &tv;
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- }
+ glib_pollfds_fill(&timeout);
if (timeout > 0) {
qemu_mutex_unlock_iothread();
}
- ret = select(nfds + 1, &rfds, &wfds, &xfds, tvarg);
+ ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout);
if (timeout > 0) {
qemu_mutex_lock_iothread();
}
- glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+ glib_pollfds_poll();
return ret;
}
#else
@@ -327,14 +293,67 @@ void qemu_fd_register(int fd)
FD_CONNECT | FD_WRITE | FD_OOB);
}
+static int pollfds_fill(GArray *pollfds, fd_set *rfds, fd_set *wfds,
+ fd_set *xfds)
+{
+ int nfds = -1;
+ int i;
+
+ for (i = 0; i < pollfds->len; i++) {
+ GPollFD *pfd = &g_array_index(pollfds, GPollFD, i);
+ int fd = pfd->fd;
+ int events = pfd->events;
+ if (events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
+ FD_SET(fd, rfds);
+ nfds = MAX(nfds, fd);
+ }
+ if (events & (G_IO_OUT | G_IO_ERR)) {
+ FD_SET(fd, wfds);
+ nfds = MAX(nfds, fd);
+ }
+ if (events & G_IO_PRI) {
+ FD_SET(fd, xfds);
+ nfds = MAX(nfds, fd);
+ }
+ }
+ return nfds;
+}
+
+static void pollfds_poll(GArray *pollfds, int nfds, fd_set *rfds,
+ fd_set *wfds, fd_set *xfds)
+{
+ int i;
+
+ for (i = 0; i < pollfds->len; i++) {
+ GPollFD *pfd = &g_array_index(pollfds, GPollFD, i);
+ int fd = pfd->fd;
+ int revents = 0;
+
+ if (FD_ISSET(fd, rfds)) {
+ revents |= G_IO_IN | G_IO_HUP | G_IO_ERR;
+ }
+ if (FD_ISSET(fd, wfds)) {
+ revents |= G_IO_OUT | G_IO_ERR;
+ }
+ if (FD_ISSET(fd, xfds)) {
+ revents |= G_IO_PRI;
+ }
+ pfd->revents = revents & pfd->events;
+ }
+}
+
static int os_host_main_loop_wait(uint32_t timeout)
{
GMainContext *context = g_main_context_default();
- int select_ret, g_poll_ret, ret, i;
+ GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
+ int select_ret = 0;
+ int g_poll_ret, ret, i, n_poll_fds;
PollingEntry *pe;
WaitObjects *w = &wait_objects;
gint poll_timeout;
static struct timeval tv0;
+ fd_set rfds, wfds, xfds;
+ int nfds;
/* XXX: need to suppress polling by better using win32 events */
ret = 0;
@@ -381,11 +400,18 @@ static int os_host_main_loop_wait(uint32_t timeout)
* improve socket latency.
*/
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
+ nfds = pollfds_fill(gpollfds, &rfds, &wfds, &xfds);
if (nfds >= 0) {
select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0);
if (select_ret != 0) {
timeout = 0;
}
+ if (select_ret > 0) {
+ pollfds_poll(gpollfds, nfds, &rfds, &wfds, &xfds);
+ }
}
return select_ret || g_poll_ret;
@@ -402,21 +428,17 @@ int main_loop_wait(int nonblocking)
}
/* poll any events */
+ g_array_set_size(gpollfds, 0); /* reset for new iteration */
/* XXX: separate device handlers from system ones */
- nfds = -1;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_ZERO(&xfds);
-
#ifdef CONFIG_SLIRP
slirp_update_timeout(&timeout);
- slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+ slirp_pollfds_fill(gpollfds);
#endif
- qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
+ qemu_iohandler_fill(gpollfds);
ret = os_host_main_loop_wait(timeout);
- qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
+ qemu_iohandler_poll(gpollfds, ret);
#ifdef CONFIG_SLIRP
- slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+ slirp_pollfds_poll(gpollfds, (ret < 0));
#endif
qemu_run_all_timers();
diff --git a/monitor.c b/monitor.c
index 6a0f2573f5..32a6e74fd9 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2740,7 +2740,7 @@ static const mon_cmd_t qmp_cmds[] = {
/*******************************************************************/
static const char *pch;
-static jmp_buf expr_env;
+static sigjmp_buf expr_env;
#define MD_TLONG 0
#define MD_I32 1
@@ -3135,7 +3135,7 @@ static const MonitorDef monitor_defs[] = {
static void expr_error(Monitor *mon, const char *msg)
{
monitor_printf(mon, "%s\n", msg);
- longjmp(expr_env, 1);
+ siglongjmp(expr_env, 1);
}
/* return 0 if OK, -1 if not found */
@@ -3345,7 +3345,7 @@ static int64_t expr_sum(Monitor *mon)
static int get_expr(Monitor *mon, int64_t *pval, const char **pp)
{
pch = *pp;
- if (setjmp(expr_env)) {
+ if (sigsetjmp(expr_env, 0)) {
*pp = pch;
return -1;
}
diff --git a/po/Makefile b/po/Makefile
new file mode 100644
index 0000000000..2b4420f178
--- /dev/null
+++ b/po/Makefile
@@ -0,0 +1,46 @@
+# This makefile is very special as it's meant to build as part of the build
+# process and also within the source tree to update the translation files.
+
+VERSION=$(shell cat ../VERSION)
+TRANSLATIONS=de_DE it
+SRCS=$(addsuffix .po, $(TRANSLATIONS))
+OBJS=$(addsuffix .mo, $(TRANSLATIONS))
+
+SRC_PATH=..
+
+-include ../config-host.mak
+
+vpath %.po $(SRC_PATH)/po
+
+all:
+ @echo Use 'make update' to update translation files
+ @echo or us 'make build' or 'make install' to build and install
+ @echo the translation files
+
+update: $(SRCS)
+
+build: $(OBJS)
+
+clean:
+ $(RM) $(OBJS)
+
+install: $(OBJS)
+ for obj in $(OBJS); do \
+ base=`basename $$obj .mo`; \
+ $(INSTALL) -d $(DESTDIR)$(prefix)/share/locale/$$base/LC_MESSAGES; \
+ $(INSTALL) -m644 $$obj $(DESTDIR)$(prefix)/share/locale/$$base/LC_MESSAGES/qemu.mo; \
+ done
+
+%.mo:
+ @msgfmt -o $@ $(SRC_PATH)/po/`basename $@ .mo`.po
+
+messages.po: $(SRC_PATH)/ui/gtk.c
+ @xgettext -o $@ --foreign-user --package-name=QEMU --package-version=1.0.50 --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $<
+
+de_DE.po: messages.po $(SRC_PATH)/ui/gtk.c
+ @msgmerge $@ $< > $@.bak && mv $@.bak $@
+
+it.po: messages.po $(SRC_PATH)/ui/gtk.c
+ @msgmerge $@ $< > $@.bak && mv $@.bak $@
+
+.PHONY: $(SRCS) clean all
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644
index 0000000000..875578349d
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,41 @@
+# German translation for QEMU.
+# This file is put in the public domain.
+# Kevin Wolf <kwolf@redhat.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2013-02-08 09:21-0600\n"
+"PO-Revision-Date: 2012-02-28 16:00+0100\n"
+"Last-Translator: Kevin Wolf <kwolf@redhat.com>\n"
+"Language-Team: Deutsch <de@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
+
+#: ../ui/gtk.c:990
+msgid "_File"
+msgstr "_Datei"
+
+#: ../ui/gtk.c:1000
+msgid "_View"
+msgstr "_Ansicht"
+
+#: ../ui/gtk.c:1029
+msgid "Zoom To _Fit"
+msgstr "Auf _Fenstergröße skalieren"
+
+#: ../ui/gtk.c:1035
+msgid "Grab On _Hover"
+msgstr "Tastatur _automatisch einfangen"
+
+#: ../ui/gtk.c:1038
+msgid "_Grab Input"
+msgstr "_Eingabegeräte einfangen"
+
+#: ../ui/gtk.c:1064
+msgid "Show _Tabs"
+msgstr "_Tableiste anzeigen"
diff --git a/po/it.po b/po/it.po
new file mode 100644
index 0000000000..7d77fff2d3
--- /dev/null
+++ b/po/it.po
@@ -0,0 +1,41 @@
+# Italian translation for QEMU.
+# This file is put in the public domain.
+# Paolo Bonzini <pbonzini@redhat.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2013-02-08 09:21-0600\n"
+"PO-Revision-Date: 2012-02-27 08:23+0100\n"
+"Last-Translator: Paolo Bonzini <pbonzini@redhat.com>\n"
+"Language-Team: Italian <it@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: ../ui/gtk.c:990
+msgid "_File"
+msgstr "_File"
+
+#: ../ui/gtk.c:1000
+msgid "_View"
+msgstr "_Visualizza"
+
+#: ../ui/gtk.c:1029
+msgid "Zoom To _Fit"
+msgstr "Adatta alla _finestra"
+
+#: ../ui/gtk.c:1035
+msgid "Grab On _Hover"
+msgstr "Cattura _automatica input"
+
+#: ../ui/gtk.c:1038
+msgid "_Grab Input"
+msgstr "_Cattura input"
+
+#: ../ui/gtk.c:1064
+msgid "Show _Tabs"
+msgstr "Mostra _tab"
diff --git a/po/messages.po b/po/messages.po
new file mode 100644
index 0000000000..191e81cc7c
--- /dev/null
+++ b/po/messages.po
@@ -0,0 +1,41 @@
+# SOME DESCRIPTIVE TITLE.
+# This file is put in the public domain.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2013-02-08 09:21-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../ui/gtk.c:990
+msgid "_File"
+msgstr ""
+
+#: ../ui/gtk.c:1000
+msgid "_View"
+msgstr ""
+
+#: ../ui/gtk.c:1029
+msgid "Zoom To _Fit"
+msgstr ""
+
+#: ../ui/gtk.c:1035
+msgid "Grab On _Hover"
+msgstr ""
+
+#: ../ui/gtk.c:1038
+msgid "_Grab Input"
+msgstr ""
+
+#: ../ui/gtk.c:1064
+msgid "Show _Tabs"
+msgstr ""
diff --git a/qapi-schema.json b/qapi-schema.json
index 7275b5dd6a..cd7ea25e4c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2504,6 +2504,9 @@
#
# @fd: #optional file descriptor of an already opened tap
#
+# @fds: #optional multiple file descriptors of already opened multiqueue capable
+# tap
+#
# @script: #optional script to initialize the interface
#
# @downscript: #optional script to shut down the interface
@@ -2518,6 +2521,9 @@
#
# @vhostfd: #optional file descriptor of an already opened vhost net device
#
+# @vhostfds: #optional file descriptors of multiple already opened vhost net
+# devices
+#
# @vhostforce: #optional vhost on for non-MSIX virtio guests
#
# Since 1.2
diff --git a/qemu-char.c b/qemu-char.c
index e4b0f5304f..160decc2f0 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2980,7 +2980,7 @@ static const struct {
{ .name = "socket", .open = qemu_chr_open_socket },
{ .name = "udp", .open = qemu_chr_open_udp },
{ .name = "msmouse", .open = qemu_chr_open_msmouse },
- { .name = "vc", .open = text_console_init },
+ { .name = "vc", .open = vc_init },
{ .name = "memory", .open = qemu_chr_open_ringbuf },
#ifdef _WIN32
{ .name = "file", .open = qemu_chr_open_win_file_out },
diff --git a/qemu-options.hx b/qemu-options.hx
index 4bc9c85d9e..2832d82148 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1354,7 +1354,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
"-net tap[,vlan=n][,name=str],ifname=name\n"
" connect the host TAP network interface to VLAN 'n'\n"
#else
- "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
+ "-net tap[,vlan=n][,name=str][,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off]\n"
" connect the host TAP network interface to VLAN 'n'\n"
" use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
" to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
@@ -1363,6 +1363,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
" use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") to\n"
" configure it\n"
" use 'fd=h' to connect to an already opened TAP interface\n"
+ " use 'fds=x:y:...:z' to connect to already opened multiqueue capable TAP interfaces\n"
" use 'sndbuf=nbytes' to limit the size of the send buffer (the\n"
" default is disabled 'sndbuf=0' to enable flow control set 'sndbuf=1048576')\n"
" use vnet_hdr=off to avoid enabling the IFF_VNET_HDR tap flag\n"
@@ -1371,6 +1372,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
" (only has effect for virtio guests which use MSIX)\n"
" use vhostforce=on to force vhost on for non-MSIX virtio guests\n"
" use 'vhostfd=h' to connect to an already opened vhost net device\n"
+ " use 'vhostfds=x:y:...:z to connect to multiple already opened vhost net devices\n"
"-net bridge[,vlan=n][,name=str][,br=bridge][,helper=helper]\n"
" connects a host TAP network interface to a host bridge device 'br'\n"
" (default=" DEFAULT_BRIDGE_INTERFACE ") using the program 'helper'\n"
diff --git a/qom/object.c b/qom/object.c
index 563e45b0cc..3d638ff273 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -245,6 +245,7 @@ static void type_initialize(TypeImpl *ti)
g_assert(parent->class_size <= ti->class_size);
memcpy(ti->class, parent->class, parent->class_size);
+ ti->class->interfaces = NULL;
for (e = parent->class->interfaces; e; e = e->next) {
ObjectClass *iface = e->data;
@@ -448,7 +449,8 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class,
TypeImpl *type = class->type;
ObjectClass *ret = NULL;
- if (type->num_interfaces && type_is_ancestor(target_type, type_interface)) {
+ if (type->class->interfaces &&
+ type_is_ancestor(target_type, type_interface)) {
int found = 0;
GSList *i;
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 49609c2ad7..ceabff81b2 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -17,11 +17,9 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
void slirp_cleanup(Slirp *slirp);
void slirp_update_timeout(uint32_t *timeout);
-void slirp_select_fill(int *pnfds,
- fd_set *readfds, fd_set *writefds, fd_set *xfds);
+void slirp_pollfds_fill(GArray *pollfds);
-void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
- int select_error);
+void slirp_pollfds_poll(GArray *pollfds, int select_error);
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
diff --git a/slirp/main.h b/slirp/main.h
index 66e4f9252f..f2e58cfe2d 100644
--- a/slirp/main.h
+++ b/slirp/main.h
@@ -31,7 +31,6 @@ extern int ctty_closed;
extern char *slirp_tty;
extern char *exec_shell;
extern u_int curtime;
-extern fd_set *global_readfds, *global_writefds, *global_xfds;
extern struct in_addr loopback_addr;
extern unsigned long loopback_mask;
extern char *username;
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 0e6e232789..bd9b7cb644 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -39,9 +39,6 @@ static const uint8_t special_ethaddr[ETH_ALEN] = {
static const uint8_t zero_ethaddr[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-/* XXX: suppress those select globals */
-fd_set *global_readfds, *global_writefds, *global_xfds;
-
u_int curtime;
static u_int time_fasttimo, last_slowtimo;
static int do_slowtimo;
@@ -261,7 +258,6 @@ void slirp_cleanup(Slirp *slirp)
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
void slirp_update_timeout(uint32_t *timeout)
{
@@ -270,156 +266,179 @@ void slirp_update_timeout(uint32_t *timeout)
}
}
-void slirp_select_fill(int *pnfds,
- fd_set *readfds, fd_set *writefds, fd_set *xfds)
+void slirp_pollfds_fill(GArray *pollfds)
{
Slirp *slirp;
struct socket *so, *so_next;
- int nfds;
if (QTAILQ_EMPTY(&slirp_instances)) {
return;
}
- /* fail safe */
- global_readfds = NULL;
- global_writefds = NULL;
- global_xfds = NULL;
-
- nfds = *pnfds;
- /*
- * First, TCP sockets
- */
- do_slowtimo = 0;
-
- QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
- /*
- * *_slowtimo needs calling if there are IP fragments
- * in the fragment queue, or there are TCP connections active
- */
- do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
- (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
-
- for (so = slirp->tcb.so_next; so != &slirp->tcb;
- so = so_next) {
- so_next = so->so_next;
-
- /*
- * See if we need a tcp_fasttimo
- */
- if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
- time_fasttimo = curtime; /* Flag when we want a fasttimo */
-
- /*
- * NOFDREF can include still connecting to local-host,
- * newly socreated() sockets etc. Don't want to select these.
- */
- if (so->so_state & SS_NOFDREF || so->s == -1)
- continue;
-
- /*
- * Set for reading sockets which are accepting
- */
- if (so->so_state & SS_FACCEPTCONN) {
- FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
- continue;
- }
-
- /*
- * Set for writing sockets which are connecting
- */
- if (so->so_state & SS_ISFCONNECTING) {
- FD_SET(so->s, writefds);
- UPD_NFDS(so->s);
- continue;
- }
-
- /*
- * Set for writing if we are connected, can send more, and
- * we have something to send
- */
- if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
- FD_SET(so->s, writefds);
- UPD_NFDS(so->s);
- }
-
- /*
- * Set for reading (and urgent data) if we are connected, can
- * receive more, and we have room for it XXX /2 ?
- */
- if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
- FD_SET(so->s, readfds);
- FD_SET(so->s, xfds);
- UPD_NFDS(so->s);
- }
- }
-
- /*
- * UDP sockets
- */
- for (so = slirp->udb.so_next; so != &slirp->udb;
- so = so_next) {
- so_next = so->so_next;
-
- /*
- * See if it's timed out
- */
- if (so->so_expire) {
- if (so->so_expire <= curtime) {
- udp_detach(so);
- continue;
- } else
- do_slowtimo = 1; /* Let socket expire */
- }
-
- /*
- * When UDP packets are received from over the
- * link, they're sendto()'d straight away, so
- * no need for setting for writing
- * Limit the number of packets queued by this session
- * to 4. Note that even though we try and limit this
- * to 4 packets, the session could have more queued
- * if the packets needed to be fragmented
- * (XXX <= 4 ?)
- */
- if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
- FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
- }
- }
+ /*
+ * First, TCP sockets
+ */
+ do_slowtimo = 0;
- /*
- * ICMP sockets
- */
- for (so = slirp->icmp.so_next; so != &slirp->icmp;
- so = so_next) {
- so_next = so->so_next;
+ QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
+ /*
+ * *_slowtimo needs calling if there are IP fragments
+ * in the fragment queue, or there are TCP connections active
+ */
+ do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
+ (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
+
+ for (so = slirp->tcb.so_next; so != &slirp->tcb;
+ so = so_next) {
+ int events = 0;
+
+ so_next = so->so_next;
+
+ so->pollfds_idx = -1;
+
+ /*
+ * See if we need a tcp_fasttimo
+ */
+ if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) {
+ time_fasttimo = curtime; /* Flag when we want a fasttimo */
+ }
- /*
- * See if it's timed out
- */
- if (so->so_expire) {
- if (so->so_expire <= curtime) {
- icmp_detach(so);
- continue;
- } else {
- do_slowtimo = 1; /* Let socket expire */
- }
- }
+ /*
+ * NOFDREF can include still connecting to local-host,
+ * newly socreated() sockets etc. Don't want to select these.
+ */
+ if (so->so_state & SS_NOFDREF || so->s == -1) {
+ continue;
+ }
- if (so->so_state & SS_ISFCONNECTED) {
- FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
- }
+ /*
+ * Set for reading sockets which are accepting
+ */
+ if (so->so_state & SS_FACCEPTCONN) {
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
+ continue;
+ }
+
+ /*
+ * Set for writing sockets which are connecting
+ */
+ if (so->so_state & SS_ISFCONNECTING) {
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = G_IO_OUT | G_IO_ERR,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
+ continue;
+ }
+
+ /*
+ * Set for writing if we are connected, can send more, and
+ * we have something to send
+ */
+ if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
+ events |= G_IO_OUT | G_IO_ERR;
+ }
+
+ /*
+ * Set for reading (and urgent data) if we are connected, can
+ * receive more, and we have room for it XXX /2 ?
+ */
+ if (CONN_CANFRCV(so) &&
+ (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
+ events |= G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
+ }
+
+ if (events) {
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = events,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
+ }
+ }
+
+ /*
+ * UDP sockets
+ */
+ for (so = slirp->udb.so_next; so != &slirp->udb;
+ so = so_next) {
+ so_next = so->so_next;
+
+ so->pollfds_idx = -1;
+
+ /*
+ * See if it's timed out
+ */
+ if (so->so_expire) {
+ if (so->so_expire <= curtime) {
+ udp_detach(so);
+ continue;
+ } else {
+ do_slowtimo = 1; /* Let socket expire */
+ }
+ }
+
+ /*
+ * When UDP packets are received from over the
+ * link, they're sendto()'d straight away, so
+ * no need for setting for writing
+ * Limit the number of packets queued by this session
+ * to 4. Note that even though we try and limit this
+ * to 4 packets, the session could have more queued
+ * if the packets needed to be fragmented
+ * (XXX <= 4 ?)
+ */
+ if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
+ }
+ }
+
+ /*
+ * ICMP sockets
+ */
+ for (so = slirp->icmp.so_next; so != &slirp->icmp;
+ so = so_next) {
+ so_next = so->so_next;
+
+ so->pollfds_idx = -1;
+
+ /*
+ * See if it's timed out
+ */
+ if (so->so_expire) {
+ if (so->so_expire <= curtime) {
+ icmp_detach(so);
+ continue;
+ } else {
+ do_slowtimo = 1; /* Let socket expire */
}
- }
+ }
- *pnfds = nfds;
+ if (so->so_state & SS_ISFCONNECTED) {
+ GPollFD pfd = {
+ .fd = so->s,
+ .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+ };
+ so->pollfds_idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
+ }
+ }
+ }
}
-void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
- int select_error)
+void slirp_pollfds_poll(GArray *pollfds, int select_error)
{
Slirp *slirp;
struct socket *so, *so_next;
@@ -429,184 +448,202 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
return;
}
- global_readfds = readfds;
- global_writefds = writefds;
- global_xfds = xfds;
-
curtime = qemu_get_clock_ms(rt_clock);
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
- /*
- * See if anything has timed out
- */
- if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
- tcp_fasttimo(slirp);
- time_fasttimo = 0;
- }
- if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
- ip_slowtimo(slirp);
- tcp_slowtimo(slirp);
- last_slowtimo = curtime;
- }
-
- /*
- * Check sockets
- */
- if (!select_error) {
- /*
- * Check TCP sockets
- */
- for (so = slirp->tcb.so_next; so != &slirp->tcb;
- so = so_next) {
- so_next = so->so_next;
-
- /*
- * FD_ISSET is meaningless on these sockets
- * (and they can crash the program)
- */
- if (so->so_state & SS_NOFDREF || so->s == -1)
- continue;
-
- /*
- * Check for URG data
- * This will soread as well, so no need to
- * test for readfds below if this succeeds
- */
- if (FD_ISSET(so->s, xfds))
- sorecvoob(so);
- /*
- * Check sockets for reading
- */
- else if (FD_ISSET(so->s, readfds)) {
- /*
- * Check for incoming connections
- */
- if (so->so_state & SS_FACCEPTCONN) {
- tcp_connect(so);
- continue;
- } /* else */
- ret = soread(so);
-
- /* Output it if we read something */
- if (ret > 0)
- tcp_output(sototcpcb(so));
- }
-
- /*
- * Check sockets for writing
- */
- if (FD_ISSET(so->s, writefds)) {
- /*
- * Check for non-blocking, still-connecting sockets
- */
- if (so->so_state & SS_ISFCONNECTING) {
- /* Connected */
- so->so_state &= ~SS_ISFCONNECTING;
-
- ret = send(so->s, (const void *) &ret, 0, 0);
- if (ret < 0) {
- /* XXXXX Must fix, zero bytes is a NOP */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN)
- continue;
-
- /* else failed */
- so->so_state &= SS_PERSISTENT_MASK;
- so->so_state |= SS_NOFDREF;
- }
- /* else so->so_state &= ~SS_ISFCONNECTING; */
-
- /*
- * Continue tcp_input
- */
- tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
- /* continue; */
- } else
- ret = sowrite(so);
- /*
- * XXXXX If we wrote something (a lot), there
- * could be a need for a window update.
- * In the worst case, the remote will send
- * a window probe to get things going again
- */
- }
-
- /*
- * Probe a still-connecting, non-blocking socket
- * to check if it's still alive
- */
-#ifdef PROBE_CONN
- if (so->so_state & SS_ISFCONNECTING) {
- ret = qemu_recv(so->s, &ret, 0,0);
-
- if (ret < 0) {
- /* XXX */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN)
- continue; /* Still connecting, continue */
-
- /* else failed */
- so->so_state &= SS_PERSISTENT_MASK;
- so->so_state |= SS_NOFDREF;
-
- /* tcp_input will take care of it */
- } else {
- ret = send(so->s, &ret, 0,0);
- if (ret < 0) {
- /* XXX */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN)
- continue;
- /* else failed */
- so->so_state &= SS_PERSISTENT_MASK;
- so->so_state |= SS_NOFDREF;
- } else
- so->so_state &= ~SS_ISFCONNECTING;
-
- }
- tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
- } /* SS_ISFCONNECTING */
-#endif
- }
-
- /*
- * Now UDP sockets.
- * Incoming packets are sent straight away, they're not buffered.
- * Incoming UDP data isn't buffered either.
- */
- for (so = slirp->udb.so_next; so != &slirp->udb;
- so = so_next) {
- so_next = so->so_next;
-
- if (so->s != -1 && FD_ISSET(so->s, readfds)) {
- sorecvfrom(so);
+ /*
+ * See if anything has timed out
+ */
+ if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
+ tcp_fasttimo(slirp);
+ time_fasttimo = 0;
+ }
+ if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
+ ip_slowtimo(slirp);
+ tcp_slowtimo(slirp);
+ last_slowtimo = curtime;
+ }
+
+ /*
+ * Check sockets
+ */
+ if (!select_error) {
+ /*
+ * Check TCP sockets
+ */
+ for (so = slirp->tcb.so_next; so != &slirp->tcb;
+ so = so_next) {
+ int revents;
+
+ so_next = so->so_next;
+
+ revents = 0;
+ if (so->pollfds_idx != -1) {
+ revents = g_array_index(pollfds, GPollFD,
+ so->pollfds_idx).revents;
+ }
+
+ if (so->so_state & SS_NOFDREF || so->s == -1) {
+ continue;
+ }
+
+ /*
+ * Check for URG data
+ * This will soread as well, so no need to
+ * test for G_IO_IN below if this succeeds
+ */
+ if (revents & G_IO_PRI) {
+ sorecvoob(so);
+ }
+ /*
+ * Check sockets for reading
+ */
+ else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
+ /*
+ * Check for incoming connections
+ */
+ if (so->so_state & SS_FACCEPTCONN) {
+ tcp_connect(so);
+ continue;
+ } /* else */
+ ret = soread(so);
+
+ /* Output it if we read something */
+ if (ret > 0) {
+ tcp_output(sototcpcb(so));
+ }
+ }
+
+ /*
+ * Check sockets for writing
+ */
+ if (!(so->so_state & SS_NOFDREF) &&
+ (revents & (G_IO_OUT | G_IO_ERR))) {
+ /*
+ * Check for non-blocking, still-connecting sockets
+ */
+ if (so->so_state & SS_ISFCONNECTING) {
+ /* Connected */
+ so->so_state &= ~SS_ISFCONNECTING;
+
+ ret = send(so->s, (const void *) &ret, 0, 0);
+ if (ret < 0) {
+ /* XXXXX Must fix, zero bytes is a NOP */
+ if (errno == EAGAIN || errno == EWOULDBLOCK ||
+ errno == EINPROGRESS || errno == ENOTCONN) {
+ continue;
+ }
+
+ /* else failed */
+ so->so_state &= SS_PERSISTENT_MASK;
+ so->so_state |= SS_NOFDREF;
}
- }
+ /* else so->so_state &= ~SS_ISFCONNECTING; */
+
+ /*
+ * Continue tcp_input
+ */
+ tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+ /* continue; */
+ } else {
+ ret = sowrite(so);
+ }
+ /*
+ * XXXXX If we wrote something (a lot), there
+ * could be a need for a window update.
+ * In the worst case, the remote will send
+ * a window probe to get things going again
+ */
+ }
/*
- * Check incoming ICMP relies.
+ * Probe a still-connecting, non-blocking socket
+ * to check if it's still alive
*/
- for (so = slirp->icmp.so_next; so != &slirp->icmp;
- so = so_next) {
- so_next = so->so_next;
+#ifdef PROBE_CONN
+ if (so->so_state & SS_ISFCONNECTING) {
+ ret = qemu_recv(so->s, &ret, 0, 0);
+
+ if (ret < 0) {
+ /* XXX */
+ if (errno == EAGAIN || errno == EWOULDBLOCK ||
+ errno == EINPROGRESS || errno == ENOTCONN) {
+ continue; /* Still connecting, continue */
+ }
+
+ /* else failed */
+ so->so_state &= SS_PERSISTENT_MASK;
+ so->so_state |= SS_NOFDREF;
+
+ /* tcp_input will take care of it */
+ } else {
+ ret = send(so->s, &ret, 0, 0);
+ if (ret < 0) {
+ /* XXX */
+ if (errno == EAGAIN || errno == EWOULDBLOCK ||
+ errno == EINPROGRESS || errno == ENOTCONN) {
+ continue;
+ }
+ /* else failed */
+ so->so_state &= SS_PERSISTENT_MASK;
+ so->so_state |= SS_NOFDREF;
+ } else {
+ so->so_state &= ~SS_ISFCONNECTING;
+ }
- if (so->s != -1 && FD_ISSET(so->s, readfds)) {
- icmp_receive(so);
}
+ tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+ } /* SS_ISFCONNECTING */
+#endif
+ }
+
+ /*
+ * Now UDP sockets.
+ * Incoming packets are sent straight away, they're not buffered.
+ * Incoming UDP data isn't buffered either.
+ */
+ for (so = slirp->udb.so_next; so != &slirp->udb;
+ so = so_next) {
+ int revents;
+
+ so_next = so->so_next;
+
+ revents = 0;
+ if (so->pollfds_idx != -1) {
+ revents = g_array_index(pollfds, GPollFD,
+ so->pollfds_idx).revents;
+ }
+
+ if (so->s != -1 &&
+ (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
+ sorecvfrom(so);
}
- }
+ }
+
+ /*
+ * Check incoming ICMP relies.
+ */
+ for (so = slirp->icmp.so_next; so != &slirp->icmp;
+ so = so_next) {
+ int revents;
+
+ so_next = so->so_next;
+
+ revents = 0;
+ if (so->pollfds_idx != -1) {
+ revents = g_array_index(pollfds, GPollFD,
+ so->pollfds_idx).revents;
+ }
+
+ if (so->s != -1 &&
+ (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
+ icmp_receive(so);
+ }
+ }
+ }
if_start(slirp);
}
-
- /* clear global file descriptor sets.
- * these reside on the stack in vl.c
- * so they're unusable if we're not in
- * slirp_select_fill or slirp_select_poll.
- */
- global_readfds = NULL;
- global_writefds = NULL;
- global_xfds = NULL;
}
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
@@ -827,12 +864,12 @@ int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
{
- if (so->s == -1 && so->extra) {
- qemu_chr_fe_write(so->extra, buf, len);
- return len;
- }
+ if (so->s == -1 && so->extra) {
+ qemu_chr_fe_write(so->extra, buf, len);
+ return len;
+ }
- return send(so->s, buf, len, flags);
+ return send(so->s, buf, len, flags);
}
static struct socket *
@@ -852,18 +889,20 @@ slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
int guest_port)
{
- struct iovec iov[2];
- struct socket *so;
+ struct iovec iov[2];
+ struct socket *so;
- so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
+ so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
- if (!so || so->so_state & SS_NOFDREF)
- return 0;
+ if (!so || so->so_state & SS_NOFDREF) {
+ return 0;
+ }
- if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
- return 0;
+ if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) {
+ return 0;
+ }
- return sopreprbuf(so, iov, NULL);
+ return sopreprbuf(so, iov, NULL);
}
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
diff --git a/slirp/socket.c b/slirp/socket.c
index 77b0c98197..a7ab933c43 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -680,9 +680,6 @@ sofcantrcvmore(struct socket *so)
{
if ((so->so_state & SS_NOFDREF) == 0) {
shutdown(so->s,0);
- if(global_writefds) {
- FD_CLR(so->s,global_writefds);
- }
}
so->so_state &= ~(SS_ISFCONNECTING);
if (so->so_state & SS_FCANTSENDMORE) {
@@ -698,12 +695,6 @@ sofcantsendmore(struct socket *so)
{
if ((so->so_state & SS_NOFDREF) == 0) {
shutdown(so->s,1); /* send FIN to fhost */
- if (global_readfds) {
- FD_CLR(so->s,global_readfds);
- }
- if (global_xfds) {
- FD_CLR(so->s,global_xfds);
- }
}
so->so_state &= ~(SS_ISFCONNECTING);
if (so->so_state & SS_FCANTRCVMORE) {
diff --git a/slirp/socket.h b/slirp/socket.h
index 857b0da311..57e0407ebc 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -20,6 +20,8 @@ struct socket {
int s; /* The actual socket */
+ int pollfds_idx; /* GPollFD GArray index */
+
Slirp *slirp; /* managing slirp instance */
/* XXX union these with not-yet-used sbuf params */
diff --git a/stubs/slirp.c b/stubs/slirp.c
index 9a3309a2b9..f1fc833f7a 100644
--- a/stubs/slirp.c
+++ b/stubs/slirp.c
@@ -5,13 +5,11 @@ void slirp_update_timeout(uint32_t *timeout)
{
}
-void slirp_select_fill(int *pnfds, fd_set *readfds,
- fd_set *writefds, fd_set *xfds)
+void slirp_pollfds_fill(GArray *pollfds)
{
}
-void slirp_select_poll(fd_set *readfds, fd_set *writefds,
- fd_set *xfds, int select_error)
+void slirp_pollfds_poll(GArray *pollfds, int select_error)
{
}
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index eac3041b87..3321fde916 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -9,7 +9,6 @@ DEF_HELPER_FLAGS_3(subqv, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(sublv, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(mullv, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(mulqv, TCG_CALL_NO_WG, i64, env, i64, i64)
-DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_NO_RWG_SE, i64, i64)
diff --git a/target-alpha/int_helper.c b/target-alpha/int_helper.c
index c9b42b6ed4..51ccd41bd2 100644
--- a/target-alpha/int_helper.c
+++ b/target-alpha/int_helper.c
@@ -22,13 +22,6 @@
#include "qemu/host-utils.h"
-uint64_t helper_umulh(uint64_t op1, uint64_t op2)
-{
- uint64_t tl, th;
- mulu64(&tl, &th, op1, op2);
- return th;
-}
-
uint64_t helper_ctpop(uint64_t arg)
{
return ctpop64(arg);
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index f687b95c63..f8f76957a9 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1390,7 +1390,6 @@ static inline void glue(gen_, name)(int ra, int rb, int rc, int islit,\
tcg_temp_free(tmp1); \
} \
}
-ARITH3(umulh)
ARITH3(cmpbge)
ARITH3(minub8)
ARITH3(minsb8)
@@ -2426,7 +2425,24 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x30:
/* UMULH */
- gen_umulh(ra, rb, rc, islit, lit);
+ {
+ TCGv low;
+ if (unlikely(rc == 31)){
+ break;
+ }
+ if (ra == 31) {
+ tcg_gen_movi_i64(cpu_ir[rc], 0);
+ break;
+ }
+ low = tcg_temp_new();
+ if (islit) {
+ tcg_gen_movi_tl(low, lit);
+ tcg_gen_mulu2_i64(low, cpu_ir[rc], cpu_ir[ra], low);
+ } else {
+ tcg_gen_mulu2_i64(low, cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+ }
+ tcg_temp_free(low);
+ }
break;
case 0x40:
/* MULL/V */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index e63da57a51..e97e1a59c7 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2893,11 +2893,6 @@ uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
return (a & mask) | (b & ~mask);
}
-uint32_t HELPER(logicq_cc)(uint64_t val)
-{
- return (val >> 32) | (val != 0);
-}
-
/* VFP support. We follow the convention used for VFP instructions:
Single precision routines have a "s" suffix, double precision a
"d" suffix. */
diff --git a/target-arm/helper.h b/target-arm/helper.h
index 8544f82a94..63ae13acff 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -46,8 +46,6 @@ DEF_HELPER_3(usat16, i32, env, i32, i32)
DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32)
-DEF_HELPER_1(logicq_cc, i32, i64)
-
DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE,
i32, i32, i32, i32)
DEF_HELPER_2(exception, void, env, i32)
@@ -142,9 +140,6 @@ DEF_HELPER_2(recpe_u32, i32, i32, env)
DEF_HELPER_2(rsqrte_u32, i32, i32, env)
DEF_HELPER_5(neon_tbl, i32, env, i32, i32, i32, i32)
-DEF_HELPER_3(adc_cc, i32, env, i32, i32)
-DEF_HELPER_3(sbc_cc, i32, env, i32, i32)
-
DEF_HELPER_3(shl_cc, i32, env, i32, i32)
DEF_HELPER_3(shr_cc, i32, env, i32, i32)
DEF_HELPER_3(sar_cc, i32, env, i32, i32)
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 99610d7734..a52231346c 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -315,36 +315,6 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
The only way to do that in TCG is a conditional branch, which clobbers
all our temporaries. For now implement these as helper functions. */
-uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
-{
- uint32_t result;
- if (!env->CF) {
- result = a + b;
- env->CF = result < a;
- } else {
- result = a + b + 1;
- env->CF = result <= a;
- }
- env->VF = (a ^ b ^ -1) & (a ^ result);
- env->NF = env->ZF = result;
- return result;
-}
-
-uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
-{
- uint32_t result;
- if (!env->CF) {
- result = a - b - 1;
- env->CF = a > b;
- } else {
- result = a - b;
- env->CF = a >= b;
- }
- env->VF = (a ^ b) & (a ^ result);
- env->NF = env->ZF = result;
- return result;
-}
-
/* Similarly for variable shift instructions. */
uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index a8893f767f..f2f649dffd 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -305,35 +305,41 @@ static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv b)
return a;
}
-/* FIXME: Most targets have native widening multiplication.
- It would be good to use that instead of a full wide multiply. */
/* 32x32->64 multiply. Marks inputs as dead. */
static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
{
- TCGv_i64 tmp1 = tcg_temp_new_i64();
- TCGv_i64 tmp2 = tcg_temp_new_i64();
+ TCGv lo = tcg_temp_new_i32();
+ TCGv hi = tcg_temp_new_i32();
+ TCGv_i64 ret;
- tcg_gen_extu_i32_i64(tmp1, a);
+ tcg_gen_mulu2_i32(lo, hi, a, b);
tcg_temp_free_i32(a);
- tcg_gen_extu_i32_i64(tmp2, b);
tcg_temp_free_i32(b);
- tcg_gen_mul_i64(tmp1, tmp1, tmp2);
- tcg_temp_free_i64(tmp2);
- return tmp1;
+
+ ret = tcg_temp_new_i64();
+ tcg_gen_concat_i32_i64(ret, lo, hi);
+ tcg_temp_free(lo);
+ tcg_temp_free(hi);
+
+ return ret;
}
static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
{
- TCGv_i64 tmp1 = tcg_temp_new_i64();
- TCGv_i64 tmp2 = tcg_temp_new_i64();
+ TCGv lo = tcg_temp_new_i32();
+ TCGv hi = tcg_temp_new_i32();
+ TCGv_i64 ret;
- tcg_gen_ext_i32_i64(tmp1, a);
+ tcg_gen_muls2_i32(lo, hi, a, b);
tcg_temp_free_i32(a);
- tcg_gen_ext_i32_i64(tmp2, b);
tcg_temp_free_i32(b);
- tcg_gen_mul_i64(tmp1, tmp1, tmp2);
- tcg_temp_free_i64(tmp2);
- return tmp1;
+
+ ret = tcg_temp_new_i64();
+ tcg_gen_concat_i32_i64(ret, lo, hi);
+ tcg_temp_free(lo);
+ tcg_temp_free(hi);
+
+ return ret;
}
/* Swap low and high halfwords. */
@@ -404,12 +410,39 @@ static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
/* dest = T0 + T1. Compute C, N, V and Z flags */
static void gen_add_CC(TCGv dest, TCGv t0, TCGv t1)
{
- TCGv tmp;
- tcg_gen_add_i32(cpu_NF, t0, t1);
+ TCGv tmp = tcg_temp_new_i32();
+ tcg_gen_movi_i32(tmp, 0);
+ tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, t1, tmp);
+ tcg_gen_mov_i32(cpu_ZF, cpu_NF);
+ tcg_gen_xor_i32(cpu_VF, cpu_NF, t0);
+ tcg_gen_xor_i32(tmp, t0, t1);
+ tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
+ tcg_temp_free_i32(tmp);
+ tcg_gen_mov_i32(dest, cpu_NF);
+}
+
+/* dest = T0 + T1 + CF. Compute C, N, V and Z flags */
+static void gen_adc_CC(TCGv dest, TCGv t0, TCGv t1)
+{
+ TCGv tmp = tcg_temp_new_i32();
+ if (TCG_TARGET_HAS_add2_i32) {
+ tcg_gen_movi_i32(tmp, 0);
+ tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp);
+ tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp);
+ } else {
+ TCGv_i64 q0 = tcg_temp_new_i64();
+ TCGv_i64 q1 = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(q0, t0);
+ tcg_gen_extu_i32_i64(q1, t1);
+ tcg_gen_add_i64(q0, q0, q1);
+ tcg_gen_extu_i32_i64(q1, cpu_CF);
+ tcg_gen_add_i64(q0, q0, q1);
+ tcg_gen_extr_i64_i32(cpu_NF, cpu_CF, q0);
+ tcg_temp_free_i64(q0);
+ tcg_temp_free_i64(q1);
+ }
tcg_gen_mov_i32(cpu_ZF, cpu_NF);
- tcg_gen_setcond_i32(TCG_COND_LTU, cpu_CF, cpu_NF, t0);
tcg_gen_xor_i32(cpu_VF, cpu_NF, t0);
- tmp = tcg_temp_new_i32();
tcg_gen_xor_i32(tmp, t0, t1);
tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
tcg_temp_free_i32(tmp);
@@ -431,6 +464,15 @@ static void gen_sub_CC(TCGv dest, TCGv t0, TCGv t1)
tcg_gen_mov_i32(dest, cpu_NF);
}
+/* dest = T0 + ~T1 + CF. Compute C, N, V and Z flags */
+static void gen_sbc_CC(TCGv dest, TCGv t0, TCGv t1)
+{
+ TCGv tmp = tcg_temp_new_i32();
+ tcg_gen_not_i32(tmp, t1);
+ gen_adc_CC(dest, t0, tmp);
+ tcg_temp_free(tmp);
+}
+
#define GEN_SHIFT(name) \
static void gen_##name(TCGv dest, TCGv t0, TCGv t1) \
{ \
@@ -6427,13 +6469,11 @@ static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
tcg_temp_free_i64(tmp);
}
-/* Set N and Z flags from a 64-bit value. */
-static void gen_logicq_cc(TCGv_i64 val)
+/* Set N and Z flags from hi|lo. */
+static void gen_logicq_cc(TCGv lo, TCGv hi)
{
- TCGv tmp = tcg_temp_new_i32();
- gen_helper_logicq_cc(tmp, val);
- gen_logic_CC(tmp);
- tcg_temp_free_i32(tmp);
+ tcg_gen_mov_i32(cpu_NF, hi);
+ tcg_gen_or_i32(cpu_ZF, lo, hi);
}
/* Load/Store exclusive instructions are implemented by remembering
@@ -7070,7 +7110,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
break;
case 0x05:
if (set_cc) {
- gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2);
+ gen_adc_CC(tmp, tmp, tmp2);
} else {
gen_add_carry(tmp, tmp, tmp2);
}
@@ -7078,7 +7118,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
break;
case 0x06:
if (set_cc) {
- gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2);
+ gen_sbc_CC(tmp, tmp, tmp2);
} else {
gen_sub_carry(tmp, tmp, tmp2);
}
@@ -7086,7 +7126,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
break;
case 0x07:
if (set_cc) {
- gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp);
+ gen_sbc_CC(tmp, tmp2, tmp);
} else {
gen_sub_carry(tmp, tmp2, tmp);
}
@@ -7213,18 +7253,22 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
tmp = load_reg(s, rs);
tmp2 = load_reg(s, rm);
if (insn & (1 << 22)) {
- tmp64 = gen_muls_i64_i32(tmp, tmp2);
+ tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);
} else {
- tmp64 = gen_mulu_i64_i32(tmp, tmp2);
+ tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);
}
if (insn & (1 << 21)) { /* mult accumulate */
- gen_addq(s, tmp64, rn, rd);
+ TCGv al = load_reg(s, rn);
+ TCGv ah = load_reg(s, rd);
+ tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, al, ah);
+ tcg_temp_free(al);
+ tcg_temp_free(ah);
}
if (insn & (1 << 20)) {
- gen_logicq_cc(tmp64);
+ gen_logicq_cc(tmp, tmp2);
}
- gen_storeq_reg(s, rn, rd, tmp64);
- tcg_temp_free_i64(tmp64);
+ store_reg(s, rn, tmp);
+ store_reg(s, rd, tmp2);
break;
default:
goto illegal_op;
@@ -7907,15 +7951,16 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCG
break;
case 10: /* adc */
if (conds)
- gen_helper_adc_cc(t0, cpu_env, t0, t1);
+ gen_adc_CC(t0, t0, t1);
else
gen_adc(t0, t1);
break;
case 11: /* sbc */
- if (conds)
- gen_helper_sbc_cc(t0, cpu_env, t0, t1);
- else
+ if (conds) {
+ gen_sbc_CC(t0, t0, t1);
+ } else {
gen_sub_carry(t0, t0, t1);
+ }
break;
case 13: /* sub */
if (conds)
@@ -9225,16 +9270,18 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
}
break;
case 0x5: /* adc */
- if (s->condexec_mask)
+ if (s->condexec_mask) {
gen_adc(tmp, tmp2);
- else
- gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2);
+ } else {
+ gen_adc_CC(tmp, tmp, tmp2);
+ }
break;
case 0x6: /* sbc */
- if (s->condexec_mask)
+ if (s->condexec_mask) {
gen_sub_carry(tmp, tmp, tmp2);
- else
- gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2);
+ } else {
+ gen_sbc_CC(tmp, tmp, tmp2);
+ }
break;
case 0x7: /* ror */
if (s->condexec_mask) {
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 04a5379775..14c167fb0b 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -340,46 +340,6 @@ static void t_gen_asr(TCGv d, TCGv a, TCGv b)
tcg_temp_free(t_31);
}
-/* 64-bit signed mul, lower result in d and upper in d2. */
-static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b)
-{
- TCGv_i64 t0, t1;
-
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
-
- tcg_gen_ext_i32_i64(t0, a);
- tcg_gen_ext_i32_i64(t1, b);
- tcg_gen_mul_i64(t0, t0, t1);
-
- tcg_gen_trunc_i64_i32(d, t0);
- tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_i32(d2, t0);
-
- tcg_temp_free_i64(t0);
- tcg_temp_free_i64(t1);
-}
-
-/* 64-bit unsigned muls, lower result in d and upper in d2. */
-static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b)
-{
- TCGv_i64 t0, t1;
-
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
-
- tcg_gen_extu_i32_i64(t0, a);
- tcg_gen_extu_i32_i64(t1, b);
- tcg_gen_mul_i64(t0, t0, t1);
-
- tcg_gen_trunc_i64_i32(d, t0);
- tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_i32(d2, t0);
-
- tcg_temp_free_i64(t0);
- tcg_temp_free_i64(t1);
-}
-
static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b)
{
int l1;
@@ -832,10 +792,10 @@ static void cris_alu_op_exec(DisasContext *dc, int op,
gen_helper_lz(dst, b);
break;
case CC_OP_MULS:
- t_gen_muls(dst, cpu_PR[PR_MOF], a, b);
+ tcg_gen_muls2_tl(dst, cpu_PR[PR_MOF], a, b);
break;
case CC_OP_MULU:
- t_gen_mulu(dst, cpu_PR[PR_MOF], a, b);
+ tcg_gen_mulu2_tl(dst, cpu_PR[PR_MOF], a, b);
break;
case CC_OP_DSTEP:
t_gen_cris_dstep(dst, a, b);
@@ -3215,8 +3175,6 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb,
int num_insns;
int max_insns;
- qemu_log_try_set_file(stderr);
-
if (env->pregs[PR_VR] == 32) {
dc->decoder = crisv32_decoder;
dc->clear_locked_irq = 0;
diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c
index 9422003f24..9daa1a06b8 100644
--- a/target-i386/cc_helper.c
+++ b/target-i386/cc_helper.c
@@ -75,243 +75,247 @@ const uint8_t parity_table[256] = {
#endif
-static int compute_all_eflags(CPUX86State *env)
+static target_ulong compute_all_adcx(target_ulong dst, target_ulong src1,
+ target_ulong src2)
{
- return CC_SRC;
+ return (src1 & ~CC_C) | (dst * CC_C);
}
-static int compute_c_eflags(CPUX86State *env)
+static target_ulong compute_all_adox(target_ulong dst, target_ulong src1,
+ target_ulong src2)
{
- return CC_SRC & CC_C;
+ return (src1 & ~CC_O) | (src2 * CC_O);
}
-uint32_t helper_cc_compute_all(CPUX86State *env, int op)
+static target_ulong compute_all_adcox(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ return (src1 & ~(CC_C | CC_O)) | (dst * CC_C) | (src2 * CC_O);
+}
+
+target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
+ target_ulong src2, int op)
{
switch (op) {
default: /* should never happen */
return 0;
case CC_OP_EFLAGS:
- return compute_all_eflags(env);
+ return src1;
+ case CC_OP_CLR:
+ return CC_Z;
case CC_OP_MULB:
- return compute_all_mulb(env);
+ return compute_all_mulb(dst, src1);
case CC_OP_MULW:
- return compute_all_mulw(env);
+ return compute_all_mulw(dst, src1);
case CC_OP_MULL:
- return compute_all_mull(env);
+ return compute_all_mull(dst, src1);
case CC_OP_ADDB:
- return compute_all_addb(env);
+ return compute_all_addb(dst, src1);
case CC_OP_ADDW:
- return compute_all_addw(env);
+ return compute_all_addw(dst, src1);
case CC_OP_ADDL:
- return compute_all_addl(env);
+ return compute_all_addl(dst, src1);
case CC_OP_ADCB:
- return compute_all_adcb(env);
+ return compute_all_adcb(dst, src1, src2);
case CC_OP_ADCW:
- return compute_all_adcw(env);
+ return compute_all_adcw(dst, src1, src2);
case CC_OP_ADCL:
- return compute_all_adcl(env);
+ return compute_all_adcl(dst, src1, src2);
case CC_OP_SUBB:
- return compute_all_subb(env);
+ return compute_all_subb(dst, src1);
case CC_OP_SUBW:
- return compute_all_subw(env);
+ return compute_all_subw(dst, src1);
case CC_OP_SUBL:
- return compute_all_subl(env);
+ return compute_all_subl(dst, src1);
case CC_OP_SBBB:
- return compute_all_sbbb(env);
+ return compute_all_sbbb(dst, src1, src2);
case CC_OP_SBBW:
- return compute_all_sbbw(env);
+ return compute_all_sbbw(dst, src1, src2);
case CC_OP_SBBL:
- return compute_all_sbbl(env);
+ return compute_all_sbbl(dst, src1, src2);
case CC_OP_LOGICB:
- return compute_all_logicb(env);
+ return compute_all_logicb(dst, src1);
case CC_OP_LOGICW:
- return compute_all_logicw(env);
+ return compute_all_logicw(dst, src1);
case CC_OP_LOGICL:
- return compute_all_logicl(env);
+ return compute_all_logicl(dst, src1);
case CC_OP_INCB:
- return compute_all_incb(env);
+ return compute_all_incb(dst, src1);
case CC_OP_INCW:
- return compute_all_incw(env);
+ return compute_all_incw(dst, src1);
case CC_OP_INCL:
- return compute_all_incl(env);
+ return compute_all_incl(dst, src1);
case CC_OP_DECB:
- return compute_all_decb(env);
+ return compute_all_decb(dst, src1);
case CC_OP_DECW:
- return compute_all_decw(env);
+ return compute_all_decw(dst, src1);
case CC_OP_DECL:
- return compute_all_decl(env);
+ return compute_all_decl(dst, src1);
case CC_OP_SHLB:
- return compute_all_shlb(env);
+ return compute_all_shlb(dst, src1);
case CC_OP_SHLW:
- return compute_all_shlw(env);
+ return compute_all_shlw(dst, src1);
case CC_OP_SHLL:
- return compute_all_shll(env);
+ return compute_all_shll(dst, src1);
case CC_OP_SARB:
- return compute_all_sarb(env);
+ return compute_all_sarb(dst, src1);
case CC_OP_SARW:
- return compute_all_sarw(env);
+ return compute_all_sarw(dst, src1);
case CC_OP_SARL:
- return compute_all_sarl(env);
+ return compute_all_sarl(dst, src1);
+
+ case CC_OP_BMILGB:
+ return compute_all_bmilgb(dst, src1);
+ case CC_OP_BMILGW:
+ return compute_all_bmilgw(dst, src1);
+ case CC_OP_BMILGL:
+ return compute_all_bmilgl(dst, src1);
+
+ case CC_OP_ADCX:
+ return compute_all_adcx(dst, src1, src2);
+ case CC_OP_ADOX:
+ return compute_all_adox(dst, src1, src2);
+ case CC_OP_ADCOX:
+ return compute_all_adcox(dst, src1, src2);
#ifdef TARGET_X86_64
case CC_OP_MULQ:
- return compute_all_mulq(env);
-
+ return compute_all_mulq(dst, src1);
case CC_OP_ADDQ:
- return compute_all_addq(env);
-
+ return compute_all_addq(dst, src1);
case CC_OP_ADCQ:
- return compute_all_adcq(env);
-
+ return compute_all_adcq(dst, src1, src2);
case CC_OP_SUBQ:
- return compute_all_subq(env);
-
+ return compute_all_subq(dst, src1);
case CC_OP_SBBQ:
- return compute_all_sbbq(env);
-
+ return compute_all_sbbq(dst, src1, src2);
case CC_OP_LOGICQ:
- return compute_all_logicq(env);
-
+ return compute_all_logicq(dst, src1);
case CC_OP_INCQ:
- return compute_all_incq(env);
-
+ return compute_all_incq(dst, src1);
case CC_OP_DECQ:
- return compute_all_decq(env);
-
+ return compute_all_decq(dst, src1);
case CC_OP_SHLQ:
- return compute_all_shlq(env);
-
+ return compute_all_shlq(dst, src1);
case CC_OP_SARQ:
- return compute_all_sarq(env);
+ return compute_all_sarq(dst, src1);
+ case CC_OP_BMILGQ:
+ return compute_all_bmilgq(dst, src1);
#endif
}
}
uint32_t cpu_cc_compute_all(CPUX86State *env, int op)
{
- return helper_cc_compute_all(env, op);
+ return helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, op);
}
-uint32_t helper_cc_compute_c(CPUX86State *env, int op)
+target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1,
+ target_ulong src2, int op)
{
switch (op) {
default: /* should never happen */
+ case CC_OP_LOGICB:
+ case CC_OP_LOGICW:
+ case CC_OP_LOGICL:
+ case CC_OP_LOGICQ:
+ case CC_OP_CLR:
return 0;
case CC_OP_EFLAGS:
- return compute_c_eflags(env);
+ case CC_OP_SARB:
+ case CC_OP_SARW:
+ case CC_OP_SARL:
+ case CC_OP_SARQ:
+ case CC_OP_ADOX:
+ return src1 & 1;
+
+ case CC_OP_INCB:
+ case CC_OP_INCW:
+ case CC_OP_INCL:
+ case CC_OP_INCQ:
+ case CC_OP_DECB:
+ case CC_OP_DECW:
+ case CC_OP_DECL:
+ case CC_OP_DECQ:
+ return src1;
case CC_OP_MULB:
- return compute_c_mull(env);
case CC_OP_MULW:
- return compute_c_mull(env);
case CC_OP_MULL:
- return compute_c_mull(env);
+ case CC_OP_MULQ:
+ return src1 != 0;
+
+ case CC_OP_ADCX:
+ case CC_OP_ADCOX:
+ return dst;
case CC_OP_ADDB:
- return compute_c_addb(env);
+ return compute_c_addb(dst, src1);
case CC_OP_ADDW:
- return compute_c_addw(env);
+ return compute_c_addw(dst, src1);
case CC_OP_ADDL:
- return compute_c_addl(env);
+ return compute_c_addl(dst, src1);
case CC_OP_ADCB:
- return compute_c_adcb(env);
+ return compute_c_adcb(dst, src1, src2);
case CC_OP_ADCW:
- return compute_c_adcw(env);
+ return compute_c_adcw(dst, src1, src2);
case CC_OP_ADCL:
- return compute_c_adcl(env);
+ return compute_c_adcl(dst, src1, src2);
case CC_OP_SUBB:
- return compute_c_subb(env);
+ return compute_c_subb(dst, src1);
case CC_OP_SUBW:
- return compute_c_subw(env);
+ return compute_c_subw(dst, src1);
case CC_OP_SUBL:
- return compute_c_subl(env);
+ return compute_c_subl(dst, src1);
case CC_OP_SBBB:
- return compute_c_sbbb(env);
+ return compute_c_sbbb(dst, src1, src2);
case CC_OP_SBBW:
- return compute_c_sbbw(env);
+ return compute_c_sbbw(dst, src1, src2);
case CC_OP_SBBL:
- return compute_c_sbbl(env);
-
- case CC_OP_LOGICB:
- return compute_c_logicb();
- case CC_OP_LOGICW:
- return compute_c_logicw();
- case CC_OP_LOGICL:
- return compute_c_logicl();
-
- case CC_OP_INCB:
- return compute_c_incl(env);
- case CC_OP_INCW:
- return compute_c_incl(env);
- case CC_OP_INCL:
- return compute_c_incl(env);
-
- case CC_OP_DECB:
- return compute_c_incl(env);
- case CC_OP_DECW:
- return compute_c_incl(env);
- case CC_OP_DECL:
- return compute_c_incl(env);
+ return compute_c_sbbl(dst, src1, src2);
case CC_OP_SHLB:
- return compute_c_shlb(env);
+ return compute_c_shlb(dst, src1);
case CC_OP_SHLW:
- return compute_c_shlw(env);
+ return compute_c_shlw(dst, src1);
case CC_OP_SHLL:
- return compute_c_shll(env);
+ return compute_c_shll(dst, src1);
- case CC_OP_SARB:
- return compute_c_sarl(env);
- case CC_OP_SARW:
- return compute_c_sarl(env);
- case CC_OP_SARL:
- return compute_c_sarl(env);
+ case CC_OP_BMILGB:
+ return compute_c_bmilgb(dst, src1);
+ case CC_OP_BMILGW:
+ return compute_c_bmilgw(dst, src1);
+ case CC_OP_BMILGL:
+ return compute_c_bmilgl(dst, src1);
#ifdef TARGET_X86_64
- case CC_OP_MULQ:
- return compute_c_mull(env);
-
case CC_OP_ADDQ:
- return compute_c_addq(env);
-
+ return compute_c_addq(dst, src1);
case CC_OP_ADCQ:
- return compute_c_adcq(env);
-
+ return compute_c_adcq(dst, src1, src2);
case CC_OP_SUBQ:
- return compute_c_subq(env);
-
+ return compute_c_subq(dst, src1);
case CC_OP_SBBQ:
- return compute_c_sbbq(env);
-
- case CC_OP_LOGICQ:
- return compute_c_logicq();
-
- case CC_OP_INCQ:
- return compute_c_incl(env);
-
- case CC_OP_DECQ:
- return compute_c_incl(env);
-
+ return compute_c_sbbq(dst, src1, src2);
case CC_OP_SHLQ:
- return compute_c_shlq(env);
-
- case CC_OP_SARQ:
- return compute_c_sarl(env);
+ return compute_c_shlq(dst, src1);
+ case CC_OP_BMILGQ:
+ return compute_c_bmilgq(dst, src1);
#endif
}
}
@@ -326,7 +330,7 @@ target_ulong helper_read_eflags(CPUX86State *env)
{
uint32_t eflags;
- eflags = helper_cc_compute_all(env, CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
eflags |= (DF & DF_MASK);
eflags |= env->eflags & ~(VM_MASK | RF_MASK);
return eflags;
diff --git a/target-i386/cc_helper_template.h b/target-i386/cc_helper_template.h
index 1f94e11dcf..607311f195 100644
--- a/target-i386/cc_helper_template.h
+++ b/target-i386/cc_helper_template.h
@@ -18,258 +18,223 @@
*/
#define DATA_BITS (1 << (3 + SHIFT))
-#define SIGN_MASK (((target_ulong)1) << (DATA_BITS - 1))
#if DATA_BITS == 8
#define SUFFIX b
#define DATA_TYPE uint8_t
-#define DATA_MASK 0xff
#elif DATA_BITS == 16
#define SUFFIX w
#define DATA_TYPE uint16_t
-#define DATA_MASK 0xffff
#elif DATA_BITS == 32
#define SUFFIX l
#define DATA_TYPE uint32_t
-#define DATA_MASK 0xffffffff
#elif DATA_BITS == 64
#define SUFFIX q
#define DATA_TYPE uint64_t
-#define DATA_MASK 0xffffffffffffffffULL
#else
#error unhandled operand size
#endif
+#define SIGN_MASK (((DATA_TYPE)1) << (DATA_BITS - 1))
+
/* dynamic flags computation */
-static int glue(compute_all_add, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
int cf, pf, af, zf, sf, of;
- target_long src1, src2;
-
- src1 = CC_SRC;
- src2 = CC_DST - CC_SRC;
- cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+ DATA_TYPE src2 = dst - src1;
+
+ cf = dst < src1;
+ pf = parity_table[(uint8_t)dst];
+ af = (dst ^ src1 ^ src2) & CC_A;
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
+ of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_add, SUFFIX)(CPUX86State *env)
+static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
- int cf;
- target_long src1;
-
- src1 = CC_SRC;
- cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
- return cf;
+ return dst < src1;
}
-static int glue(compute_all_adc, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
+ DATA_TYPE src3)
{
int cf, pf, af, zf, sf, of;
- target_long src1, src2;
-
- src1 = CC_SRC;
- src2 = CC_DST - CC_SRC - 1;
- cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+ DATA_TYPE src2 = dst - src1 - src3;
+
+ cf = (src3 ? dst <= src1 : dst < src1);
+ pf = parity_table[(uint8_t)dst];
+ af = (dst ^ src1 ^ src2) & 0x10;
+ zf = (dst == 0) << 6;
+ sf = lshift(dst, 8 - DATA_BITS) & 0x80;
+ of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_adc, SUFFIX)(CPUX86State *env)
+static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
+ DATA_TYPE src3)
{
- int cf;
- target_long src1;
-
- src1 = CC_SRC;
- cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
- return cf;
+ return src3 ? dst <= src1 : dst < src1;
}
-static int glue(compute_all_sub, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
{
int cf, pf, af, zf, sf, of;
- target_long src1, src2;
-
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
- cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+ DATA_TYPE src1 = dst + src2;
+
+ cf = src1 < src2;
+ pf = parity_table[(uint8_t)dst];
+ af = (dst ^ src1 ^ src2) & CC_A;
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
+ of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_sub, SUFFIX)(CPUX86State *env)
+static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
{
- int cf;
- target_long src1, src2;
+ DATA_TYPE src1 = dst + src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
- cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
- return cf;
+ return src1 < src2;
}
-static int glue(compute_all_sbb, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
+ DATA_TYPE src3)
{
int cf, pf, af, zf, sf, of;
- target_long src1, src2;
-
- src1 = CC_DST + CC_SRC + 1;
- src2 = CC_SRC;
- cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+ DATA_TYPE src1 = dst + src2 + src3;
+
+ cf = (src3 ? src1 <= src2 : src1 < src2);
+ pf = parity_table[(uint8_t)dst];
+ af = (dst ^ src1 ^ src2) & 0x10;
+ zf = (dst == 0) << 6;
+ sf = lshift(dst, 8 - DATA_BITS) & 0x80;
+ of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_sbb, SUFFIX)(CPUX86State *env)
+static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
+ DATA_TYPE src3)
{
- int cf;
- target_long src1, src2;
+ DATA_TYPE src1 = dst + src2 + src3;
- src1 = CC_DST + CC_SRC + 1;
- src2 = CC_SRC;
- cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
- return cf;
+ return (src3 ? src1 <= src2 : src1 < src2);
}
-static int glue(compute_all_logic, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
int cf, pf, af, zf, sf, of;
cf = 0;
- pf = parity_table[(uint8_t)CC_DST];
+ pf = parity_table[(uint8_t)dst];
af = 0;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
of = 0;
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_logic, SUFFIX)(void)
-{
- return 0;
-}
-
-static int glue(compute_all_inc, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
int cf, pf, af, zf, sf, of;
- target_long src1, src2;
+ DATA_TYPE src2;
- src1 = CC_DST - 1;
+ cf = src1;
+ src1 = dst - 1;
src2 = 1;
- cf = CC_SRC;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11;
+ pf = parity_table[(uint8_t)dst];
+ af = (dst ^ src1 ^ src2) & CC_A;
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
+ of = (dst == SIGN_MASK) * CC_O;
return cf | pf | af | zf | sf | of;
}
-#if DATA_BITS == 32
-static int glue(compute_c_inc, SUFFIX)(CPUX86State *env)
-{
- return CC_SRC;
-}
-#endif
-
-static int glue(compute_all_dec, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
int cf, pf, af, zf, sf, of;
- target_long src1, src2;
+ DATA_TYPE src2;
- src1 = CC_DST + 1;
+ cf = src1;
+ src1 = dst + 1;
src2 = 1;
- cf = CC_SRC;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = ((CC_DST & DATA_MASK) == ((target_ulong)SIGN_MASK - 1)) << 11;
+ pf = parity_table[(uint8_t)dst];
+ af = (dst ^ src1 ^ src2) & CC_A;
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
+ of = (dst == SIGN_MASK - 1) * CC_O;
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_all_shl, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
int cf, pf, af, zf, sf, of;
- cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C;
- pf = parity_table[(uint8_t)CC_DST];
+ cf = (src1 >> (DATA_BITS - 1)) & CC_C;
+ pf = parity_table[(uint8_t)dst];
af = 0; /* undefined */
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- /* of is defined if shift count == 1 */
- of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
+ /* of is defined iff shift count == 1 */
+ of = lshift(src1 ^ dst, 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_shl, SUFFIX)(CPUX86State *env)
-{
- return (CC_SRC >> (DATA_BITS - 1)) & CC_C;
-}
-
-#if DATA_BITS == 32
-static int glue(compute_c_sar, SUFFIX)(CPUX86State *env)
+static int glue(compute_c_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
- return CC_SRC & 1;
+ return (src1 >> (DATA_BITS - 1)) & CC_C;
}
-#endif
-static int glue(compute_all_sar, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_sar, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
int cf, pf, af, zf, sf, of;
- cf = CC_SRC & 1;
- pf = parity_table[(uint8_t)CC_DST];
+ cf = src1 & 1;
+ pf = parity_table[(uint8_t)dst];
af = 0; /* undefined */
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- /* of is defined if shift count == 1 */
- of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
+ /* of is defined iff shift count == 1 */
+ of = lshift(src1 ^ dst, 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
-#if DATA_BITS == 32
-static int glue(compute_c_mul, SUFFIX)(CPUX86State *env)
+/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
+ CF are modified and it is slower to do that. Note as well that we
+ don't truncate SRC1 for computing carry to DATA_TYPE. */
+static int glue(compute_all_mul, SUFFIX)(DATA_TYPE dst, target_long src1)
{
- int cf;
+ int cf, pf, af, zf, sf, of;
- cf = (CC_SRC != 0);
- return cf;
+ cf = (src1 != 0);
+ pf = parity_table[(uint8_t)dst];
+ af = 0; /* undefined */
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
+ of = cf * CC_O;
+ return cf | pf | af | zf | sf | of;
}
-#endif
-/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
- CF are modified and it is slower to do that. */
-static int glue(compute_all_mul, SUFFIX)(CPUX86State *env)
+static int glue(compute_all_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
int cf, pf, af, zf, sf, of;
- cf = (CC_SRC != 0);
- pf = parity_table[(uint8_t)CC_DST];
+ cf = (src1 == 0);
+ pf = 0; /* undefined */
af = 0; /* undefined */
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = cf << 11;
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
+ of = 0;
return cf | pf | af | zf | sf | of;
}
+static int glue(compute_c_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
+{
+ return src1 == 0;
+}
+
#undef DATA_BITS
#undef SIGN_MASK
#undef DATA_TYPE
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index dfcf86e862..5582e5f4e6 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -389,10 +389,15 @@ typedef struct x86_def_t {
CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */
#define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | \
CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT | \
- CPUID_EXT_HYPERVISOR)
+ CPUID_EXT_MOVBE | CPUID_EXT_HYPERVISOR)
/* missing:
- CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_EST,
- CPUID_EXT_TM2, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_XSAVE */
+ CPUID_EXT_PCLMULQDQ, CPUID_EXT_DTES64, CPUID_EXT_DSCPL,
+ CPUID_EXT_VMX, CPUID_EXT_SMX, CPUID_EXT_EST, CPUID_EXT_TM2,
+ CPUID_EXT_CID, CPUID_EXT_FMA, CPUID_EXT_XTPR, CPUID_EXT_PDCM,
+ CPUID_EXT_PCID, CPUID_EXT_DCA, CPUID_EXT_SSE41, CPUID_EXT_SSE42,
+ CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_AES,
+ CPUID_EXT_XSAVE, CPUID_EXT_OSXSAVE, CPUID_EXT_AVX,
+ CPUID_EXT_F16C, CPUID_EXT_RDRAND */
#define TCG_EXT2_FEATURES ((TCG_FEATURES & CPUID_EXT2_AMD_ALIASES) | \
CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \
CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT)
@@ -401,7 +406,12 @@ typedef struct x86_def_t {
#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
#define TCG_SVM_FEATURES 0
-#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP)
+#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP \
+ CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX)
+ /* missing:
+ CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2,
+ CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
+ CPUID_7_0_EBX_RDSEED */
/* built-in CPU model definitions
*/
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 7577e4f8bb..493dda8bb6 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -582,7 +582,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define CPU_INTERRUPT_TPR CPU_INTERRUPT_TGT_INT_3
-enum {
+typedef enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
CC_OP_EFLAGS, /* all cc are explicitly computed, CC_SRC = flags */
@@ -636,8 +636,19 @@ enum {
CC_OP_SARL,
CC_OP_SARQ,
+ CC_OP_BMILGB, /* Z,S via CC_DST, C = SRC==0; O=0; P,A undefined */
+ CC_OP_BMILGW,
+ CC_OP_BMILGL,
+ CC_OP_BMILGQ,
+
+ CC_OP_ADCX, /* CC_DST = C, CC_SRC = rest. */
+ CC_OP_ADOX, /* CC_DST = O, CC_SRC = rest. */
+ CC_OP_ADCOX, /* CC_DST = C, CC_SRC2 = O, CC_SRC = rest. */
+
+ CC_OP_CLR, /* Z set, all other flags clear. */
+
CC_OP_NB,
-};
+} CCOp;
typedef struct SegmentCache {
uint32_t selector;
@@ -725,8 +736,9 @@ typedef struct CPUX86State {
stored elsewhere */
/* emulator internal eflags handling */
- target_ulong cc_src;
target_ulong cc_dst;
+ target_ulong cc_src;
+ target_ulong cc_src2;
uint32_t cc_op;
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
uint32_t hflags; /* TB flags, see HF_xxx constants. These flags
@@ -764,7 +776,6 @@ typedef struct CPUX86State {
XMMReg xmm_regs[CPU_NB_REGS];
XMMReg xmm_t0;
MMXReg mmx_t0;
- target_ulong cc_tmp; /* temporary for rcr/rcl */
/* sysenter registers */
uint32_t sysenter_cs;
@@ -1117,9 +1128,10 @@ static inline int cpu_mmu_index (CPUX86State *env)
#define EIP (env->eip)
#define DF (env->df)
-#define CC_SRC (env->cc_src)
-#define CC_DST (env->cc_dst)
-#define CC_OP (env->cc_op)
+#define CC_DST (env->cc_dst)
+#define CC_SRC (env->cc_src)
+#define CC_SRC2 (env->cc_src2)
+#define CC_OP (env->cc_op)
/* n must be a constant to be efficient */
static inline target_long lshift(target_long x, int n)
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 4bf9db7f7d..82a731c77d 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -55,7 +55,7 @@ int cpu_x86_support_mca_broadcast(CPUX86State *env)
/***********************************************************/
/* x86 debug */
-static const char *cc_op_str[] = {
+static const char *cc_op_str[CC_OP_NB] = {
"DYNAMIC",
"EFLAGS",
@@ -108,6 +108,17 @@ static const char *cc_op_str[] = {
"SARW",
"SARL",
"SARQ",
+
+ "BMILGB",
+ "BMILGW",
+ "BMILGL",
+ "BMILGQ",
+
+ "ADCX",
+ "ADOX",
+ "ADCOX",
+
+ "CLR",
};
static void
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 9ed720d0ed..26a0cc80a4 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -1,7 +1,7 @@
#include "exec/def-helper.h"
-DEF_HELPER_FLAGS_2(cc_compute_all, TCG_CALL_NO_SE, i32, env, int)
-DEF_HELPER_FLAGS_2(cc_compute_c, TCG_CALL_NO_SE, i32, env, int)
+DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
+DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
DEF_HELPER_0(lock, void)
DEF_HELPER_0(unlock, void)
@@ -19,6 +19,7 @@ DEF_HELPER_2(imulq_EAX_T0, void, env, tl)
DEF_HELPER_3(imulq_T0_T1, tl, env, tl, tl)
DEF_HELPER_2(divq_EAX, void, env, tl)
DEF_HELPER_2(idivq_EAX, void, env, tl)
+DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#endif
DEF_HELPER_2(aam, void, env, int)
@@ -193,9 +194,11 @@ DEF_HELPER_3(fsave, void, env, tl, int)
DEF_HELPER_3(frstor, void, env, tl, int)
DEF_HELPER_3(fxsave, void, env, tl, int)
DEF_HELPER_3(fxrstor, void, env, tl, int)
-DEF_HELPER_1(bsf, tl, tl)
-DEF_HELPER_1(bsr, tl, tl)
-DEF_HELPER_2(lzcnt, tl, tl, int)
+
+DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
+DEF_HELPER_FLAGS_1(ctz, TCG_CALL_NO_RWG_SE, tl, tl)
+DEF_HELPER_FLAGS_2(pdep, TCG_CALL_NO_RWG_SE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(pext, TCG_CALL_NO_RWG_SE, tl, tl, tl)
/* MMX/SSE */
diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c
index 84b812dcca..3b56075a9d 100644
--- a/target-i386/int_helper.c
+++ b/target-i386/int_helper.c
@@ -385,6 +385,13 @@ void helper_mulq_EAX_T0(CPUX86State *env, target_ulong t0)
CC_SRC = r1;
}
+target_ulong helper_umulh(target_ulong t0, target_ulong t1)
+{
+ uint64_t h, l;
+ mulu64(&l, &h, t0, t1);
+ return h;
+}
+
void helper_imulq_EAX_T0(CPUX86State *env, target_ulong t0)
{
uint64_t r0, r1;
@@ -440,45 +447,49 @@ void helper_idivq_EAX(CPUX86State *env, target_ulong t0)
}
#endif
+#if TARGET_LONG_BITS == 32
+# define ctztl ctz32
+# define clztl clz32
+#else
+# define ctztl ctz64
+# define clztl clz64
+#endif
+
/* bit operations */
-target_ulong helper_bsf(target_ulong t0)
+target_ulong helper_ctz(target_ulong t0)
{
- int count;
- target_ulong res;
-
- res = t0;
- count = 0;
- while ((res & 1) == 0) {
- count++;
- res >>= 1;
- }
- return count;
+ return ctztl(t0);
}
-target_ulong helper_lzcnt(target_ulong t0, int wordsize)
+target_ulong helper_clz(target_ulong t0)
{
- int count;
- target_ulong res, mask;
+ return clztl(t0);
+}
- if (wordsize > 0 && t0 == 0) {
- return wordsize;
- }
- res = t0;
- count = TARGET_LONG_BITS - 1;
- mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
- while ((res & mask) == 0) {
- count--;
- res <<= 1;
- }
- if (wordsize > 0) {
- return wordsize - 1 - count;
+target_ulong helper_pdep(target_ulong src, target_ulong mask)
+{
+ target_ulong dest = 0;
+ int i, o;
+
+ for (i = 0; mask != 0; i++) {
+ o = ctztl(mask);
+ mask &= mask - 1;
+ dest |= ((src >> i) & 1) << o;
}
- return count;
+ return dest;
}
-target_ulong helper_bsr(target_ulong t0)
+target_ulong helper_pext(target_ulong src, target_ulong mask)
{
- return helper_lzcnt(t0, 0);
+ target_ulong dest = 0;
+ int i, o;
+
+ for (o = 0; mask != 0; o++) {
+ i = ctztl(mask);
+ mask &= mask - 1;
+ dest |= ((src >> i) & 1) << o;
+ }
+ return dest;
}
#define SHIFT 0
diff --git a/target-i386/shift_helper_template.h b/target-i386/shift_helper_template.h
index dda0da30cf..cf91a2d284 100644
--- a/target-i386/shift_helper_template.h
+++ b/target-i386/shift_helper_template.h
@@ -55,7 +55,7 @@ target_ulong glue(helper_rcl, SUFFIX)(CPUX86State *env, target_ulong t0,
count = rclb_table[count];
#endif
if (count) {
- eflags = helper_cc_compute_all(env, CC_OP);
+ eflags = env->cc_src;
t0 &= DATA_MASK;
src = t0;
res = (t0 << count) | ((target_ulong)(eflags & CC_C) << (count - 1));
@@ -63,11 +63,9 @@ target_ulong glue(helper_rcl, SUFFIX)(CPUX86State *env, target_ulong t0,
res |= t0 >> (DATA_BITS + 1 - count);
}
t0 = res;
- env->cc_tmp = (eflags & ~(CC_C | CC_O)) |
+ env->cc_src = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (DATA_BITS - count)) & CC_C);
- } else {
- env->cc_tmp = -1;
}
return t0;
}
@@ -86,7 +84,7 @@ target_ulong glue(helper_rcr, SUFFIX)(CPUX86State *env, target_ulong t0,
count = rclb_table[count];
#endif
if (count) {
- eflags = helper_cc_compute_all(env, CC_OP);
+ eflags = env->cc_src;
t0 &= DATA_MASK;
src = t0;
res = (t0 >> count) |
@@ -95,11 +93,9 @@ target_ulong glue(helper_rcr, SUFFIX)(CPUX86State *env, target_ulong t0,
res |= t0 << (DATA_BITS + 1 - count);
}
t0 = res;
- env->cc_tmp = (eflags & ~(CC_C | CC_O)) |
+ env->cc_src = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (count - 1)) & CC_C);
- } else {
- env->cc_tmp = -1;
}
return t0;
}
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 112c3102a0..605cd88bd2 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <signal.h>
+#include "qemu/host-utils.h"
#include "cpu.h"
#include "disas/disas.h"
#include "tcg-op.h"
@@ -36,6 +37,7 @@
#define PREFIX_LOCK 0x04
#define PREFIX_DATA 0x08
#define PREFIX_ADR 0x10
+#define PREFIX_VEX 0x20
#ifdef TARGET_X86_64
#define CODE64(s) ((s)->code64)
@@ -47,21 +49,29 @@
#define REX_B(s) 0
#endif
+#ifdef TARGET_X86_64
+# define ctztl ctz64
+# define clztl clz64
+#else
+# define ctztl ctz32
+# define clztl clz32
+#endif
+
//#define MACRO_TEST 1
/* global register indexes */
static TCGv_ptr cpu_env;
-static TCGv cpu_A0, cpu_cc_src, cpu_cc_dst, cpu_cc_tmp;
+static TCGv cpu_A0;
+static TCGv cpu_cc_dst, cpu_cc_src, cpu_cc_src2, cpu_cc_srcT;
static TCGv_i32 cpu_cc_op;
static TCGv cpu_regs[CPU_NB_REGS];
/* local temps */
-static TCGv cpu_T[2], cpu_T3;
+static TCGv cpu_T[2];
/* local register indexes (only used inside old micro ops) */
static TCGv cpu_tmp0, cpu_tmp4;
static TCGv_ptr cpu_ptr0, cpu_ptr1;
static TCGv_i32 cpu_tmp2_i32, cpu_tmp3_i32;
static TCGv_i64 cpu_tmp1_i64;
-static TCGv cpu_tmp5;
static uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
@@ -88,8 +98,11 @@ typedef struct DisasContext {
int code64; /* 64 bit code segment */
int rex_x, rex_b;
#endif
+ int vex_l; /* vex vector length */
+ int vex_v; /* vex vvvv register, without 1's compliment. */
int ss32; /* 32 bit stack segment */
- int cc_op; /* current CC operation */
+ CCOp cc_op; /* current CC operation */
+ bool cc_op_dirty;
int addseg; /* non zero if either DS/ES/SS have a non zero base */
int f_st; /* currently unused */
int vm86; /* vm86 mode */
@@ -113,6 +126,7 @@ typedef struct DisasContext {
static void gen_eob(DisasContext *s);
static void gen_jmp(DisasContext *s, target_ulong eip);
static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
+static void gen_op(DisasContext *s1, int op, int ot, int d);
/* i386 arith/logic operations */
enum {
@@ -173,6 +187,79 @@ enum {
OR_A0, /* temporary register used when doing address evaluation */
};
+enum {
+ USES_CC_DST = 1,
+ USES_CC_SRC = 2,
+ USES_CC_SRC2 = 4,
+ USES_CC_SRCT = 8,
+};
+
+/* Bit set if the global variable is live after setting CC_OP to X. */
+static const uint8_t cc_op_live[CC_OP_NB] = {
+ [CC_OP_DYNAMIC] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
+ [CC_OP_EFLAGS] = USES_CC_SRC,
+ [CC_OP_MULB ... CC_OP_MULQ] = USES_CC_DST | USES_CC_SRC,
+ [CC_OP_ADDB ... CC_OP_ADDQ] = USES_CC_DST | USES_CC_SRC,
+ [CC_OP_ADCB ... CC_OP_ADCQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
+ [CC_OP_SUBB ... CC_OP_SUBQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRCT,
+ [CC_OP_SBBB ... CC_OP_SBBQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
+ [CC_OP_LOGICB ... CC_OP_LOGICQ] = USES_CC_DST,
+ [CC_OP_INCB ... CC_OP_INCQ] = USES_CC_DST | USES_CC_SRC,
+ [CC_OP_DECB ... CC_OP_DECQ] = USES_CC_DST | USES_CC_SRC,
+ [CC_OP_SHLB ... CC_OP_SHLQ] = USES_CC_DST | USES_CC_SRC,
+ [CC_OP_SARB ... CC_OP_SARQ] = USES_CC_DST | USES_CC_SRC,
+ [CC_OP_BMILGB ... CC_OP_BMILGQ] = USES_CC_DST | USES_CC_SRC,
+ [CC_OP_ADCX] = USES_CC_DST | USES_CC_SRC,
+ [CC_OP_ADOX] = USES_CC_SRC | USES_CC_SRC2,
+ [CC_OP_ADCOX] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
+ [CC_OP_CLR] = 0,
+};
+
+static void set_cc_op(DisasContext *s, CCOp op)
+{
+ int dead;
+
+ if (s->cc_op == op) {
+ return;
+ }
+
+ /* Discard CC computation that will no longer be used. */
+ dead = cc_op_live[s->cc_op] & ~cc_op_live[op];
+ if (dead & USES_CC_DST) {
+ tcg_gen_discard_tl(cpu_cc_dst);
+ }
+ if (dead & USES_CC_SRC) {
+ tcg_gen_discard_tl(cpu_cc_src);
+ }
+ if (dead & USES_CC_SRC2) {
+ tcg_gen_discard_tl(cpu_cc_src2);
+ }
+ if (dead & USES_CC_SRCT) {
+ tcg_gen_discard_tl(cpu_cc_srcT);
+ }
+
+ if (op == CC_OP_DYNAMIC) {
+ /* The DYNAMIC setting is translator only, and should never be
+ stored. Thus we always consider it clean. */
+ s->cc_op_dirty = false;
+ } else {
+ /* Discard any computed CC_OP value (see shifts). */
+ if (s->cc_op == CC_OP_DYNAMIC) {
+ tcg_gen_discard_i32(cpu_cc_op);
+ }
+ s->cc_op_dirty = true;
+ }
+ s->cc_op = op;
+}
+
+static void gen_update_cc_op(DisasContext *s)
+{
+ if (s->cc_op_dirty) {
+ tcg_gen_movi_i32(cpu_cc_op, s->cc_op);
+ s->cc_op_dirty = false;
+ }
+}
+
static inline void gen_op_movl_T0_0(void)
{
tcg_gen_movi_tl(cpu_T[0], 0);
@@ -323,17 +410,17 @@ static inline void gen_op_mov_reg_T1(int ot, int reg)
static inline void gen_op_mov_reg_A0(int size, int reg)
{
switch(size) {
- case 0:
+ case OT_BYTE:
tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_A0, 0, 16);
break;
default: /* XXX this shouldn't be reached; abort? */
- case 1:
+ case OT_WORD:
/* For x86_64, this sets the higher half of register to zero.
For i386, this is equivalent to a mov. */
tcg_gen_ext32u_tl(cpu_regs[reg], cpu_A0);
break;
#ifdef TARGET_X86_64
- case 2:
+ case OT_LONG:
tcg_gen_mov_tl(cpu_regs[reg], cpu_A0);
break;
#endif
@@ -398,11 +485,11 @@ static inline void gen_op_jmp_T0(void)
static inline void gen_op_add_reg_im(int size, int reg, int32_t val)
{
switch(size) {
- case 0:
+ case OT_BYTE:
tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16);
break;
- case 1:
+ case OT_WORD:
tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
/* For x86_64, this sets the higher half of register to zero.
For i386, this is equivalent to a nop. */
@@ -410,7 +497,7 @@ static inline void gen_op_add_reg_im(int size, int reg, int32_t val)
tcg_gen_mov_tl(cpu_regs[reg], cpu_tmp0);
break;
#ifdef TARGET_X86_64
- case 2:
+ case OT_LONG:
tcg_gen_addi_tl(cpu_regs[reg], cpu_regs[reg], val);
break;
#endif
@@ -420,11 +507,11 @@ static inline void gen_op_add_reg_im(int size, int reg, int32_t val)
static inline void gen_op_add_reg_T0(int size, int reg)
{
switch(size) {
- case 0:
+ case OT_BYTE:
tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16);
break;
- case 1:
+ case OT_WORD:
tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
/* For x86_64, this sets the higher half of register to zero.
For i386, this is equivalent to a nop. */
@@ -432,18 +519,13 @@ static inline void gen_op_add_reg_T0(int size, int reg)
tcg_gen_mov_tl(cpu_regs[reg], cpu_tmp0);
break;
#ifdef TARGET_X86_64
- case 2:
+ case OT_LONG:
tcg_gen_add_tl(cpu_regs[reg], cpu_regs[reg], cpu_T[0]);
break;
#endif
}
}
-static inline void gen_op_set_cc_op(int32_t val)
-{
- tcg_gen_movi_i32(cpu_cc_op, val);
-}
-
static inline void gen_op_addl_A0_reg_sN(int shift, int reg)
{
tcg_gen_mov_tl(cpu_tmp0, cpu_regs[reg]);
@@ -506,14 +588,14 @@ static inline void gen_op_lds_T0_A0(int idx)
{
int mem_index = (idx >> 2) - 1;
switch(idx & 3) {
- case 0:
+ case OT_BYTE:
tcg_gen_qemu_ld8s(cpu_T[0], cpu_A0, mem_index);
break;
- case 1:
+ case OT_WORD:
tcg_gen_qemu_ld16s(cpu_T[0], cpu_A0, mem_index);
break;
default:
- case 2:
+ case OT_LONG:
tcg_gen_qemu_ld32s(cpu_T[0], cpu_A0, mem_index);
break;
}
@@ -523,17 +605,17 @@ static inline void gen_op_ld_v(int idx, TCGv t0, TCGv a0)
{
int mem_index = (idx >> 2) - 1;
switch(idx & 3) {
- case 0:
+ case OT_BYTE:
tcg_gen_qemu_ld8u(t0, a0, mem_index);
break;
- case 1:
+ case OT_WORD:
tcg_gen_qemu_ld16u(t0, a0, mem_index);
break;
- case 2:
+ case OT_LONG:
tcg_gen_qemu_ld32u(t0, a0, mem_index);
break;
default:
- case 3:
+ case OT_QUAD:
/* Should never happen on 32-bit targets. */
#ifdef TARGET_X86_64
tcg_gen_qemu_ld64(t0, a0, mem_index);
@@ -562,17 +644,17 @@ static inline void gen_op_st_v(int idx, TCGv t0, TCGv a0)
{
int mem_index = (idx >> 2) - 1;
switch(idx & 3) {
- case 0:
+ case OT_BYTE:
tcg_gen_qemu_st8(t0, a0, mem_index);
break;
- case 1:
+ case OT_WORD:
tcg_gen_qemu_st16(t0, a0, mem_index);
break;
- case 2:
+ case OT_LONG:
tcg_gen_qemu_st32(t0, a0, mem_index);
break;
default:
- case 3:
+ case OT_QUAD:
/* Should never happen on 32-bit targets. */
#ifdef TARGET_X86_64
tcg_gen_qemu_st64(t0, a0, mem_index);
@@ -659,38 +741,45 @@ static inline void gen_op_movl_T0_Dshift(int ot)
tcg_gen_shli_tl(cpu_T[0], cpu_T[0], ot);
};
-static void gen_extu(int ot, TCGv reg)
+static TCGv gen_ext_tl(TCGv dst, TCGv src, int size, bool sign)
{
- switch(ot) {
+ switch (size) {
case OT_BYTE:
- tcg_gen_ext8u_tl(reg, reg);
- break;
+ if (sign) {
+ tcg_gen_ext8s_tl(dst, src);
+ } else {
+ tcg_gen_ext8u_tl(dst, src);
+ }
+ return dst;
case OT_WORD:
- tcg_gen_ext16u_tl(reg, reg);
- break;
+ if (sign) {
+ tcg_gen_ext16s_tl(dst, src);
+ } else {
+ tcg_gen_ext16u_tl(dst, src);
+ }
+ return dst;
+#ifdef TARGET_X86_64
case OT_LONG:
- tcg_gen_ext32u_tl(reg, reg);
- break;
+ if (sign) {
+ tcg_gen_ext32s_tl(dst, src);
+ } else {
+ tcg_gen_ext32u_tl(dst, src);
+ }
+ return dst;
+#endif
default:
- break;
+ return src;
}
}
+static void gen_extu(int ot, TCGv reg)
+{
+ gen_ext_tl(reg, reg, ot, false);
+}
+
static void gen_exts(int ot, TCGv reg)
{
- switch(ot) {
- case OT_BYTE:
- tcg_gen_ext8s_tl(reg, reg);
- break;
- case OT_WORD:
- tcg_gen_ext16s_tl(reg, reg);
- break;
- case OT_LONG:
- tcg_gen_ext32s_tl(reg, reg);
- break;
- default:
- break;
- }
+ gen_ext_tl(reg, reg, ot, true);
}
static inline void gen_op_jnz_ecx(int size, int label1)
@@ -710,21 +799,31 @@ static inline void gen_op_jz_ecx(int size, int label1)
static void gen_helper_in_func(int ot, TCGv v, TCGv_i32 n)
{
switch (ot) {
- case 0: gen_helper_inb(v, n); break;
- case 1: gen_helper_inw(v, n); break;
- case 2: gen_helper_inl(v, n); break;
+ case OT_BYTE:
+ gen_helper_inb(v, n);
+ break;
+ case OT_WORD:
+ gen_helper_inw(v, n);
+ break;
+ case OT_LONG:
+ gen_helper_inl(v, n);
+ break;
}
-
}
static void gen_helper_out_func(int ot, TCGv_i32 v, TCGv_i32 n)
{
switch (ot) {
- case 0: gen_helper_outb(v, n); break;
- case 1: gen_helper_outw(v, n); break;
- case 2: gen_helper_outl(v, n); break;
+ case OT_BYTE:
+ gen_helper_outb(v, n);
+ break;
+ case OT_WORD:
+ gen_helper_outw(v, n);
+ break;
+ case OT_LONG:
+ gen_helper_outl(v, n);
+ break;
}
-
}
static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip,
@@ -735,27 +834,25 @@ static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip,
state_saved = 0;
if (s->pe && (s->cpl > s->iopl || s->vm86)) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(cur_eip);
state_saved = 1;
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
switch (ot) {
- case 0:
+ case OT_BYTE:
gen_helper_check_iob(cpu_env, cpu_tmp2_i32);
break;
- case 1:
+ case OT_WORD:
gen_helper_check_iow(cpu_env, cpu_tmp2_i32);
break;
- case 2:
+ case OT_LONG:
gen_helper_check_iol(cpu_env, cpu_tmp2_i32);
break;
}
}
if(s->flags & HF_SVMI_MASK) {
if (!state_saved) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(cur_eip);
}
svm_flags |= (1 << (4 + ot));
@@ -778,17 +875,8 @@ static inline void gen_movs(DisasContext *s, int ot)
gen_op_add_reg_T0(s->aflag, R_EDI);
}
-static inline void gen_update_cc_op(DisasContext *s)
-{
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
-}
-
static void gen_op_update1_cc(void)
{
- tcg_gen_discard_tl(cpu_cc_src);
tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
}
@@ -798,338 +886,392 @@ static void gen_op_update2_cc(void)
tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
}
-static inline void gen_op_cmpl_T0_T1_cc(void)
+static void gen_op_update3_cc(TCGv reg)
{
+ tcg_gen_mov_tl(cpu_cc_src2, reg);
tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
- tcg_gen_sub_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]);
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
}
static inline void gen_op_testl_T0_T1_cc(void)
{
- tcg_gen_discard_tl(cpu_cc_src);
tcg_gen_and_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]);
}
static void gen_op_update_neg_cc(void)
{
- tcg_gen_neg_tl(cpu_cc_src, cpu_T[0]);
tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+ tcg_gen_neg_tl(cpu_cc_src, cpu_T[0]);
+ tcg_gen_movi_tl(cpu_cc_srcT, 0);
}
-/* compute eflags.C to reg */
-static void gen_compute_eflags_c(TCGv reg)
+/* compute all eflags to cc_src */
+static void gen_compute_eflags(DisasContext *s)
{
- gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op);
- tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32);
+ TCGv zero, dst, src1, src2;
+ int live, dead;
+
+ if (s->cc_op == CC_OP_EFLAGS) {
+ return;
+ }
+ if (s->cc_op == CC_OP_CLR) {
+ tcg_gen_movi_tl(cpu_cc_src, CC_Z);
+ set_cc_op(s, CC_OP_EFLAGS);
+ return;
+ }
+
+ TCGV_UNUSED(zero);
+ dst = cpu_cc_dst;
+ src1 = cpu_cc_src;
+ src2 = cpu_cc_src2;
+
+ /* Take care to not read values that are not live. */
+ live = cc_op_live[s->cc_op] & ~USES_CC_SRCT;
+ dead = live ^ (USES_CC_DST | USES_CC_SRC | USES_CC_SRC2);
+ if (dead) {
+ zero = tcg_const_tl(0);
+ if (dead & USES_CC_DST) {
+ dst = zero;
+ }
+ if (dead & USES_CC_SRC) {
+ src1 = zero;
+ }
+ if (dead & USES_CC_SRC2) {
+ src2 = zero;
+ }
+ }
+
+ gen_update_cc_op(s);
+ gen_helper_cc_compute_all(cpu_cc_src, dst, src1, src2, cpu_cc_op);
+ set_cc_op(s, CC_OP_EFLAGS);
+
+ if (dead) {
+ tcg_temp_free(zero);
+ }
}
-/* compute all eflags to cc_src */
-static void gen_compute_eflags(TCGv reg)
+typedef struct CCPrepare {
+ TCGCond cond;
+ TCGv reg;
+ TCGv reg2;
+ target_ulong imm;
+ target_ulong mask;
+ bool use_reg2;
+ bool no_setcond;
+} CCPrepare;
+
+/* compute eflags.C to reg */
+static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
+{
+ TCGv t0, t1;
+ int size, shift;
+
+ switch (s->cc_op) {
+ case CC_OP_SUBB ... CC_OP_SUBQ:
+ /* (DATA_TYPE)CC_SRCT < (DATA_TYPE)CC_SRC */
+ size = s->cc_op - CC_OP_SUBB;
+ t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false);
+ /* If no temporary was used, be careful not to alias t1 and t0. */
+ t0 = TCGV_EQUAL(t1, cpu_cc_src) ? cpu_tmp0 : reg;
+ tcg_gen_mov_tl(t0, cpu_cc_srcT);
+ gen_extu(size, t0);
+ goto add_sub;
+
+ case CC_OP_ADDB ... CC_OP_ADDQ:
+ /* (DATA_TYPE)CC_DST < (DATA_TYPE)CC_SRC */
+ size = s->cc_op - CC_OP_ADDB;
+ t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false);
+ t0 = gen_ext_tl(reg, cpu_cc_dst, size, false);
+ add_sub:
+ return (CCPrepare) { .cond = TCG_COND_LTU, .reg = t0,
+ .reg2 = t1, .mask = -1, .use_reg2 = true };
+
+ case CC_OP_LOGICB ... CC_OP_LOGICQ:
+ case CC_OP_CLR:
+ return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
+
+ case CC_OP_INCB ... CC_OP_INCQ:
+ case CC_OP_DECB ... CC_OP_DECQ:
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = -1, .no_setcond = true };
+
+ case CC_OP_SHLB ... CC_OP_SHLQ:
+ /* (CC_SRC >> (DATA_BITS - 1)) & 1 */
+ size = s->cc_op - CC_OP_SHLB;
+ shift = (8 << size) - 1;
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = (target_ulong)1 << shift };
+
+ case CC_OP_MULB ... CC_OP_MULQ:
+ return (CCPrepare) { .cond = TCG_COND_NE,
+ .reg = cpu_cc_src, .mask = -1 };
+
+ case CC_OP_BMILGB ... CC_OP_BMILGQ:
+ size = s->cc_op - CC_OP_BMILGB;
+ t0 = gen_ext_tl(reg, cpu_cc_src, size, false);
+ return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 };
+
+ case CC_OP_ADCX:
+ case CC_OP_ADCOX:
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_dst,
+ .mask = -1, .no_setcond = true };
+
+ case CC_OP_EFLAGS:
+ case CC_OP_SARB ... CC_OP_SARQ:
+ /* CC_SRC & 1 */
+ return (CCPrepare) { .cond = TCG_COND_NE,
+ .reg = cpu_cc_src, .mask = CC_C };
+
+ default:
+ /* The need to compute only C from CC_OP_DYNAMIC is important
+ in efficiently implementing e.g. INC at the start of a TB. */
+ gen_update_cc_op(s);
+ gen_helper_cc_compute_c(reg, cpu_cc_dst, cpu_cc_src,
+ cpu_cc_src2, cpu_cc_op);
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg,
+ .mask = -1, .no_setcond = true };
+ }
+}
+
+/* compute eflags.P to reg */
+static CCPrepare gen_prepare_eflags_p(DisasContext *s, TCGv reg)
{
- gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_env, cpu_cc_op);
- tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32);
+ gen_compute_eflags(s);
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = CC_P };
}
-static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op)
+/* compute eflags.S to reg */
+static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg)
{
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- switch(jcc_op) {
- case JCC_O:
- gen_compute_eflags(cpu_T[0]);
- tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 11);
- tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
- break;
- case JCC_B:
- gen_compute_eflags_c(cpu_T[0]);
- break;
- case JCC_Z:
- gen_compute_eflags(cpu_T[0]);
- tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 6);
- tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
- break;
- case JCC_BE:
- gen_compute_eflags(cpu_tmp0);
- tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 6);
- tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
- tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
- break;
- case JCC_S:
- gen_compute_eflags(cpu_T[0]);
- tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 7);
- tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
- break;
- case JCC_P:
- gen_compute_eflags(cpu_T[0]);
- tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 2);
- tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
- break;
- case JCC_L:
- gen_compute_eflags(cpu_tmp0);
- tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */
- tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 7); /* CC_S */
- tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
- tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
- break;
+ switch (s->cc_op) {
+ case CC_OP_DYNAMIC:
+ gen_compute_eflags(s);
+ /* FALLTHRU */
+ case CC_OP_EFLAGS:
+ case CC_OP_ADCX:
+ case CC_OP_ADOX:
+ case CC_OP_ADCOX:
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = CC_S };
+ case CC_OP_CLR:
+ return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
default:
- case JCC_LE:
- gen_compute_eflags(cpu_tmp0);
- tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */
- tcg_gen_shri_tl(cpu_tmp4, cpu_tmp0, 7); /* CC_S */
- tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 6); /* CC_Z */
- tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp4);
- tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
- tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
- break;
+ {
+ int size = (s->cc_op - CC_OP_ADDB) & 3;
+ TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true);
+ return (CCPrepare) { .cond = TCG_COND_LT, .reg = t0, .mask = -1 };
+ }
}
}
-/* return true if setcc_slow is not needed (WARNING: must be kept in
- sync with gen_jcc1) */
-static int is_fast_jcc_case(DisasContext *s, int b)
+/* compute eflags.O to reg */
+static CCPrepare gen_prepare_eflags_o(DisasContext *s, TCGv reg)
{
- int jcc_op;
- jcc_op = (b >> 1) & 7;
- switch(s->cc_op) {
- /* we optimize the cmp/jcc case */
- case CC_OP_SUBB:
- case CC_OP_SUBW:
- case CC_OP_SUBL:
- case CC_OP_SUBQ:
- if (jcc_op == JCC_O || jcc_op == JCC_P)
- goto slow_jcc;
- break;
+ switch (s->cc_op) {
+ case CC_OP_ADOX:
+ case CC_OP_ADCOX:
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src2,
+ .mask = -1, .no_setcond = true };
+ case CC_OP_CLR:
+ return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
+ default:
+ gen_compute_eflags(s);
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = CC_O };
+ }
+}
- /* some jumps are easy to compute */
- case CC_OP_ADDB:
- case CC_OP_ADDW:
- case CC_OP_ADDL:
- case CC_OP_ADDQ:
-
- case CC_OP_LOGICB:
- case CC_OP_LOGICW:
- case CC_OP_LOGICL:
- case CC_OP_LOGICQ:
-
- case CC_OP_INCB:
- case CC_OP_INCW:
- case CC_OP_INCL:
- case CC_OP_INCQ:
-
- case CC_OP_DECB:
- case CC_OP_DECW:
- case CC_OP_DECL:
- case CC_OP_DECQ:
-
- case CC_OP_SHLB:
- case CC_OP_SHLW:
- case CC_OP_SHLL:
- case CC_OP_SHLQ:
- if (jcc_op != JCC_Z && jcc_op != JCC_S)
- goto slow_jcc;
- break;
+/* compute eflags.Z to reg */
+static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
+{
+ switch (s->cc_op) {
+ case CC_OP_DYNAMIC:
+ gen_compute_eflags(s);
+ /* FALLTHRU */
+ case CC_OP_EFLAGS:
+ case CC_OP_ADCX:
+ case CC_OP_ADOX:
+ case CC_OP_ADCOX:
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = CC_Z };
+ case CC_OP_CLR:
+ return (CCPrepare) { .cond = TCG_COND_ALWAYS, .mask = -1 };
default:
- slow_jcc:
- return 0;
+ {
+ int size = (s->cc_op - CC_OP_ADDB) & 3;
+ TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false);
+ return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 };
+ }
}
- return 1;
}
-/* generate a conditional jump to label 'l1' according to jump opcode
+/* perform a conditional store into register 'reg' according to jump opcode
value 'b'. In the fast case, T0 is guaranted not to be used. */
-static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1)
+static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg)
{
int inv, jcc_op, size, cond;
+ CCPrepare cc;
TCGv t0;
inv = b & 1;
jcc_op = (b >> 1) & 7;
- switch(cc_op) {
- /* we optimize the cmp/jcc case */
- case CC_OP_SUBB:
- case CC_OP_SUBW:
- case CC_OP_SUBL:
- case CC_OP_SUBQ:
-
- size = cc_op - CC_OP_SUBB;
- switch(jcc_op) {
- case JCC_Z:
- fast_jcc_z:
- switch(size) {
- case 0:
- tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xff);
- t0 = cpu_tmp0;
- break;
- case 1:
- tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffff);
- t0 = cpu_tmp0;
- break;
-#ifdef TARGET_X86_64
- case 2:
- tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffffffff);
- t0 = cpu_tmp0;
- break;
-#endif
- default:
- t0 = cpu_cc_dst;
- break;
- }
- tcg_gen_brcondi_tl(inv ? TCG_COND_NE : TCG_COND_EQ, t0, 0, l1);
- break;
- case JCC_S:
- fast_jcc_s:
- switch(size) {
- case 0:
- tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80);
- tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0,
- 0, l1);
- break;
- case 1:
- tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x8000);
- tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0,
- 0, l1);
- break;
-#ifdef TARGET_X86_64
- case 2:
- tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80000000);
- tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0,
- 0, l1);
- break;
-#endif
- default:
- tcg_gen_brcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, cpu_cc_dst,
- 0, l1);
- break;
- }
- break;
-
- case JCC_B:
- cond = inv ? TCG_COND_GEU : TCG_COND_LTU;
- goto fast_jcc_b;
+ switch (s->cc_op) {
+ case CC_OP_SUBB ... CC_OP_SUBQ:
+ /* We optimize relational operators for the cmp/jcc case. */
+ size = s->cc_op - CC_OP_SUBB;
+ switch (jcc_op) {
case JCC_BE:
- cond = inv ? TCG_COND_GTU : TCG_COND_LEU;
- fast_jcc_b:
- tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src);
- switch(size) {
- case 0:
- t0 = cpu_tmp0;
- tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xff);
- tcg_gen_andi_tl(t0, cpu_cc_src, 0xff);
- break;
- case 1:
- t0 = cpu_tmp0;
- tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffff);
- tcg_gen_andi_tl(t0, cpu_cc_src, 0xffff);
- break;
-#ifdef TARGET_X86_64
- case 2:
- t0 = cpu_tmp0;
- tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffffffff);
- tcg_gen_andi_tl(t0, cpu_cc_src, 0xffffffff);
- break;
-#endif
- default:
- t0 = cpu_cc_src;
- break;
- }
- tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1);
+ tcg_gen_mov_tl(cpu_tmp4, cpu_cc_srcT);
+ gen_extu(size, cpu_tmp4);
+ t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false);
+ cc = (CCPrepare) { .cond = TCG_COND_LEU, .reg = cpu_tmp4,
+ .reg2 = t0, .mask = -1, .use_reg2 = true };
break;
-
+
case JCC_L:
- cond = inv ? TCG_COND_GE : TCG_COND_LT;
+ cond = TCG_COND_LT;
goto fast_jcc_l;
case JCC_LE:
- cond = inv ? TCG_COND_GT : TCG_COND_LE;
+ cond = TCG_COND_LE;
fast_jcc_l:
- tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src);
- switch(size) {
- case 0:
- t0 = cpu_tmp0;
- tcg_gen_ext8s_tl(cpu_tmp4, cpu_tmp4);
- tcg_gen_ext8s_tl(t0, cpu_cc_src);
- break;
- case 1:
- t0 = cpu_tmp0;
- tcg_gen_ext16s_tl(cpu_tmp4, cpu_tmp4);
- tcg_gen_ext16s_tl(t0, cpu_cc_src);
- break;
-#ifdef TARGET_X86_64
- case 2:
- t0 = cpu_tmp0;
- tcg_gen_ext32s_tl(cpu_tmp4, cpu_tmp4);
- tcg_gen_ext32s_tl(t0, cpu_cc_src);
- break;
-#endif
- default:
- t0 = cpu_cc_src;
- break;
- }
- tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1);
+ tcg_gen_mov_tl(cpu_tmp4, cpu_cc_srcT);
+ gen_exts(size, cpu_tmp4);
+ t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, true);
+ cc = (CCPrepare) { .cond = cond, .reg = cpu_tmp4,
+ .reg2 = t0, .mask = -1, .use_reg2 = true };
break;
-
+
default:
goto slow_jcc;
}
break;
-
- /* some jumps are easy to compute */
- case CC_OP_ADDB:
- case CC_OP_ADDW:
- case CC_OP_ADDL:
- case CC_OP_ADDQ:
-
- case CC_OP_ADCB:
- case CC_OP_ADCW:
- case CC_OP_ADCL:
- case CC_OP_ADCQ:
-
- case CC_OP_SBBB:
- case CC_OP_SBBW:
- case CC_OP_SBBL:
- case CC_OP_SBBQ:
-
- case CC_OP_LOGICB:
- case CC_OP_LOGICW:
- case CC_OP_LOGICL:
- case CC_OP_LOGICQ:
-
- case CC_OP_INCB:
- case CC_OP_INCW:
- case CC_OP_INCL:
- case CC_OP_INCQ:
-
- case CC_OP_DECB:
- case CC_OP_DECW:
- case CC_OP_DECL:
- case CC_OP_DECQ:
-
- case CC_OP_SHLB:
- case CC_OP_SHLW:
- case CC_OP_SHLL:
- case CC_OP_SHLQ:
-
- case CC_OP_SARB:
- case CC_OP_SARW:
- case CC_OP_SARL:
- case CC_OP_SARQ:
- switch(jcc_op) {
+
+ default:
+ slow_jcc:
+ /* This actually generates good code for JC, JZ and JS. */
+ switch (jcc_op) {
+ case JCC_O:
+ cc = gen_prepare_eflags_o(s, reg);
+ break;
+ case JCC_B:
+ cc = gen_prepare_eflags_c(s, reg);
+ break;
case JCC_Z:
- size = (cc_op - CC_OP_ADDB) & 3;
- goto fast_jcc_z;
+ cc = gen_prepare_eflags_z(s, reg);
+ break;
+ case JCC_BE:
+ gen_compute_eflags(s);
+ cc = (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = CC_Z | CC_C };
+ break;
case JCC_S:
- size = (cc_op - CC_OP_ADDB) & 3;
- goto fast_jcc_s;
+ cc = gen_prepare_eflags_s(s, reg);
+ break;
+ case JCC_P:
+ cc = gen_prepare_eflags_p(s, reg);
+ break;
+ case JCC_L:
+ gen_compute_eflags(s);
+ if (TCGV_EQUAL(reg, cpu_cc_src)) {
+ reg = cpu_tmp0;
+ }
+ tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */
+ tcg_gen_xor_tl(reg, reg, cpu_cc_src);
+ cc = (CCPrepare) { .cond = TCG_COND_NE, .reg = reg,
+ .mask = CC_S };
+ break;
default:
- goto slow_jcc;
+ case JCC_LE:
+ gen_compute_eflags(s);
+ if (TCGV_EQUAL(reg, cpu_cc_src)) {
+ reg = cpu_tmp0;
+ }
+ tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */
+ tcg_gen_xor_tl(reg, reg, cpu_cc_src);
+ cc = (CCPrepare) { .cond = TCG_COND_NE, .reg = reg,
+ .mask = CC_S | CC_Z };
+ break;
}
break;
- default:
- slow_jcc:
- gen_setcc_slow_T0(s, jcc_op);
- tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE,
- cpu_T[0], 0, l1);
- break;
+ }
+
+ if (inv) {
+ cc.cond = tcg_invert_cond(cc.cond);
+ }
+ return cc;
+}
+
+static void gen_setcc1(DisasContext *s, int b, TCGv reg)
+{
+ CCPrepare cc = gen_prepare_cc(s, b, reg);
+
+ if (cc.no_setcond) {
+ if (cc.cond == TCG_COND_EQ) {
+ tcg_gen_xori_tl(reg, cc.reg, 1);
+ } else {
+ tcg_gen_mov_tl(reg, cc.reg);
+ }
+ return;
+ }
+
+ if (cc.cond == TCG_COND_NE && !cc.use_reg2 && cc.imm == 0 &&
+ cc.mask != 0 && (cc.mask & (cc.mask - 1)) == 0) {
+ tcg_gen_shri_tl(reg, cc.reg, ctztl(cc.mask));
+ tcg_gen_andi_tl(reg, reg, 1);
+ return;
+ }
+ if (cc.mask != -1) {
+ tcg_gen_andi_tl(reg, cc.reg, cc.mask);
+ cc.reg = reg;
+ }
+ if (cc.use_reg2) {
+ tcg_gen_setcond_tl(cc.cond, reg, cc.reg, cc.reg2);
+ } else {
+ tcg_gen_setcondi_tl(cc.cond, reg, cc.reg, cc.imm);
+ }
+}
+
+static inline void gen_compute_eflags_c(DisasContext *s, TCGv reg)
+{
+ gen_setcc1(s, JCC_B << 1, reg);
+}
+
+/* generate a conditional jump to label 'l1' according to jump opcode
+ value 'b'. In the fast case, T0 is guaranted not to be used. */
+static inline void gen_jcc1_noeob(DisasContext *s, int b, int l1)
+{
+ CCPrepare cc = gen_prepare_cc(s, b, cpu_T[0]);
+
+ if (cc.mask != -1) {
+ tcg_gen_andi_tl(cpu_T[0], cc.reg, cc.mask);
+ cc.reg = cpu_T[0];
+ }
+ if (cc.use_reg2) {
+ tcg_gen_brcond_tl(cc.cond, cc.reg, cc.reg2, l1);
+ } else {
+ tcg_gen_brcondi_tl(cc.cond, cc.reg, cc.imm, l1);
+ }
+}
+
+/* Generate a conditional jump to label 'l1' according to jump opcode
+ value 'b'. In the fast case, T0 is guaranted not to be used.
+ A translation block must end soon. */
+static inline void gen_jcc1(DisasContext *s, int b, int l1)
+{
+ CCPrepare cc = gen_prepare_cc(s, b, cpu_T[0]);
+
+ gen_update_cc_op(s);
+ if (cc.mask != -1) {
+ tcg_gen_andi_tl(cpu_T[0], cc.reg, cc.mask);
+ cc.reg = cpu_T[0];
+ }
+ set_cc_op(s, CC_OP_DYNAMIC);
+ if (cc.use_reg2) {
+ tcg_gen_brcond_tl(cc.cond, cc.reg, cc.reg2, l1);
+ } else {
+ tcg_gen_brcondi_tl(cc.cond, cc.reg, cc.imm, l1);
}
}
@@ -1168,21 +1310,19 @@ static inline void gen_lods(DisasContext *s, int ot)
static inline void gen_scas(DisasContext *s, int ot)
{
- gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
gen_string_movl_A0_EDI(s);
gen_op_ld_T1_A0(ot + s->mem_index);
- gen_op_cmpl_T0_T1_cc();
+ gen_op(s, OP_CMPL, ot, R_EAX);
gen_op_movl_T0_Dshift(ot);
gen_op_add_reg_T0(s->aflag, R_EDI);
}
static inline void gen_cmps(DisasContext *s, int ot)
{
- gen_string_movl_A0_ESI(s);
- gen_op_ld_T0_A0(ot + s->mem_index);
gen_string_movl_A0_EDI(s);
gen_op_ld_T1_A0(ot + s->mem_index);
- gen_op_cmpl_T0_T1_cc();
+ gen_string_movl_A0_ESI(s);
+ gen_op(s, OP_CMPL, ot, OR_TMP0);
gen_op_movl_T0_Dshift(ot);
gen_op_add_reg_T0(s->aflag, R_ESI);
gen_op_add_reg_T0(s->aflag, R_EDI);
@@ -1256,8 +1396,8 @@ static inline void gen_repz_ ## op(DisasContext *s, int ot, \
l2 = gen_jz_ecx_string(s, next_eip); \
gen_ ## op(s, ot); \
gen_op_add_reg_im(s->aflag, R_ECX, -1); \
- gen_op_set_cc_op(CC_OP_SUBB + ot); \
- gen_jcc1(s, CC_OP_SUBB + ot, (JCC_Z << 1) | (nz ^ 1), l2); \
+ gen_update_cc_op(s); \
+ gen_jcc1(s, (JCC_Z << 1) | (nz ^ 1), l2); \
if (!s->jmp_opt) \
gen_op_jz_ecx(s->aflag, l2); \
gen_jmp(s, cur_eip); \
@@ -1337,38 +1477,26 @@ static void gen_op(DisasContext *s1, int op, int ot, int d)
}
switch(op) {
case OP_ADCL:
- if (s1->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s1->cc_op);
- gen_compute_eflags_c(cpu_tmp4);
+ gen_compute_eflags_c(s1, cpu_tmp4);
tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_tmp4);
if (d != OR_TMP0)
gen_op_mov_reg_T0(ot, d);
else
gen_op_st_T0_A0(ot + s1->mem_index);
- tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
- tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
- tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4);
- tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2);
- tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_ADDB + ot);
- s1->cc_op = CC_OP_DYNAMIC;
+ gen_op_update3_cc(cpu_tmp4);
+ set_cc_op(s1, CC_OP_ADCB + ot);
break;
case OP_SBBL:
- if (s1->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s1->cc_op);
- gen_compute_eflags_c(cpu_tmp4);
+ gen_compute_eflags_c(s1, cpu_tmp4);
tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4);
if (d != OR_TMP0)
gen_op_mov_reg_T0(ot, d);
else
gen_op_st_T0_A0(ot + s1->mem_index);
- tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
- tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
- tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4);
- tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2);
- tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_SUBB + ot);
- s1->cc_op = CC_OP_DYNAMIC;
+ gen_op_update3_cc(cpu_tmp4);
+ set_cc_op(s1, CC_OP_SBBB + ot);
break;
case OP_ADDL:
gen_op_addl_T0_T1();
@@ -1377,16 +1505,17 @@ static void gen_op(DisasContext *s1, int op, int ot, int d)
else
gen_op_st_T0_A0(ot + s1->mem_index);
gen_op_update2_cc();
- s1->cc_op = CC_OP_ADDB + ot;
+ set_cc_op(s1, CC_OP_ADDB + ot);
break;
case OP_SUBL:
+ tcg_gen_mov_tl(cpu_cc_srcT, cpu_T[0]);
tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
if (d != OR_TMP0)
gen_op_mov_reg_T0(ot, d);
else
gen_op_st_T0_A0(ot + s1->mem_index);
gen_op_update2_cc();
- s1->cc_op = CC_OP_SUBB + ot;
+ set_cc_op(s1, CC_OP_SUBB + ot);
break;
default:
case OP_ANDL:
@@ -1396,7 +1525,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d)
else
gen_op_st_T0_A0(ot + s1->mem_index);
gen_op_update1_cc();
- s1->cc_op = CC_OP_LOGICB + ot;
+ set_cc_op(s1, CC_OP_LOGICB + ot);
break;
case OP_ORL:
tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
@@ -1405,7 +1534,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d)
else
gen_op_st_T0_A0(ot + s1->mem_index);
gen_op_update1_cc();
- s1->cc_op = CC_OP_LOGICB + ot;
+ set_cc_op(s1, CC_OP_LOGICB + ot);
break;
case OP_XORL:
tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
@@ -1414,11 +1543,13 @@ static void gen_op(DisasContext *s1, int op, int ot, int d)
else
gen_op_st_T0_A0(ot + s1->mem_index);
gen_op_update1_cc();
- s1->cc_op = CC_OP_LOGICB + ot;
+ set_cc_op(s1, CC_OP_LOGICB + ot);
break;
case OP_CMPL:
- gen_op_cmpl_T0_T1_cc();
- s1->cc_op = CC_OP_SUBB + ot;
+ tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
+ tcg_gen_mov_tl(cpu_cc_srcT, cpu_T[0]);
+ tcg_gen_sub_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]);
+ set_cc_op(s1, CC_OP_SUBB + ot);
break;
}
}
@@ -1430,36 +1561,71 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c)
gen_op_mov_TN_reg(ot, 0, d);
else
gen_op_ld_T0_A0(ot + s1->mem_index);
- if (s1->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s1->cc_op);
+ gen_compute_eflags_c(s1, cpu_cc_src);
if (c > 0) {
tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1);
- s1->cc_op = CC_OP_INCB + ot;
+ set_cc_op(s1, CC_OP_INCB + ot);
} else {
tcg_gen_addi_tl(cpu_T[0], cpu_T[0], -1);
- s1->cc_op = CC_OP_DECB + ot;
+ set_cc_op(s1, CC_OP_DECB + ot);
}
if (d != OR_TMP0)
gen_op_mov_reg_T0(ot, d);
else
gen_op_st_T0_A0(ot + s1->mem_index);
- gen_compute_eflags_c(cpu_cc_src);
tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
}
-static void gen_shift_rm_T1(DisasContext *s, int ot, int op1,
- int is_right, int is_arith)
+static void gen_shift_flags(DisasContext *s, int ot, TCGv result, TCGv shm1,
+ TCGv count, bool is_right)
{
- target_ulong mask;
- int shift_label;
- TCGv t0, t1, t2;
+ TCGv_i32 z32, s32, oldop;
+ TCGv z_tl;
+
+ /* Store the results into the CC variables. If we know that the
+ variable must be dead, store unconditionally. Otherwise we'll
+ need to not disrupt the current contents. */
+ z_tl = tcg_const_tl(0);
+ if (cc_op_live[s->cc_op] & USES_CC_DST) {
+ tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_dst, count, z_tl,
+ result, cpu_cc_dst);
+ } else {
+ tcg_gen_mov_tl(cpu_cc_dst, result);
+ }
+ if (cc_op_live[s->cc_op] & USES_CC_SRC) {
+ tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_src, count, z_tl,
+ shm1, cpu_cc_src);
+ } else {
+ tcg_gen_mov_tl(cpu_cc_src, shm1);
+ }
+ tcg_temp_free(z_tl);
- if (ot == OT_QUAD) {
- mask = 0x3f;
+ /* Get the two potential CC_OP values into temporaries. */
+ tcg_gen_movi_i32(cpu_tmp2_i32, (is_right ? CC_OP_SARB : CC_OP_SHLB) + ot);
+ if (s->cc_op == CC_OP_DYNAMIC) {
+ oldop = cpu_cc_op;
} else {
- mask = 0x1f;
+ tcg_gen_movi_i32(cpu_tmp3_i32, s->cc_op);
+ oldop = cpu_tmp3_i32;
}
+ /* Conditionally store the CC_OP value. */
+ z32 = tcg_const_i32(0);
+ s32 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(s32, count);
+ tcg_gen_movcond_i32(TCG_COND_NE, cpu_cc_op, s32, z32, cpu_tmp2_i32, oldop);
+ tcg_temp_free_i32(z32);
+ tcg_temp_free_i32(s32);
+
+ /* The CC_OP value is no longer predictable. */
+ set_cc_op(s, CC_OP_DYNAMIC);
+}
+
+static void gen_shift_rm_T1(DisasContext *s, int ot, int op1,
+ int is_right, int is_arith)
+{
+ target_ulong mask = (ot == OT_QUAD ? 0x3f : 0x1f);
+
/* load */
if (op1 == OR_TMP0) {
gen_op_ld_T0_A0(ot + s->mem_index);
@@ -1467,25 +1633,22 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1,
gen_op_mov_TN_reg(ot, 0, op1);
}
- t0 = tcg_temp_local_new();
- t1 = tcg_temp_local_new();
- t2 = tcg_temp_local_new();
-
- tcg_gen_andi_tl(t2, cpu_T[1], mask);
+ tcg_gen_andi_tl(cpu_T[1], cpu_T[1], mask);
+ tcg_gen_subi_tl(cpu_tmp0, cpu_T[1], 1);
if (is_right) {
if (is_arith) {
gen_exts(ot, cpu_T[0]);
- tcg_gen_mov_tl(t0, cpu_T[0]);
- tcg_gen_sar_tl(cpu_T[0], cpu_T[0], t2);
+ tcg_gen_sar_tl(cpu_tmp0, cpu_T[0], cpu_tmp0);
+ tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
} else {
gen_extu(ot, cpu_T[0]);
- tcg_gen_mov_tl(t0, cpu_T[0]);
- tcg_gen_shr_tl(cpu_T[0], cpu_T[0], t2);
+ tcg_gen_shr_tl(cpu_tmp0, cpu_T[0], cpu_tmp0);
+ tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
}
} else {
- tcg_gen_mov_tl(t0, cpu_T[0]);
- tcg_gen_shl_tl(cpu_T[0], cpu_T[0], t2);
+ tcg_gen_shl_tl(cpu_tmp0, cpu_T[0], cpu_tmp0);
+ tcg_gen_shl_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
}
/* store */
@@ -1495,52 +1658,13 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1,
gen_op_mov_reg_T0(ot, op1);
}
- /* update eflags if non zero shift */
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- }
-
- tcg_gen_mov_tl(t1, cpu_T[0]);
-
- shift_label = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, shift_label);
-
- tcg_gen_addi_tl(t2, t2, -1);
- tcg_gen_mov_tl(cpu_cc_dst, t1);
-
- if (is_right) {
- if (is_arith) {
- tcg_gen_sar_tl(cpu_cc_src, t0, t2);
- } else {
- tcg_gen_shr_tl(cpu_cc_src, t0, t2);
- }
- } else {
- tcg_gen_shl_tl(cpu_cc_src, t0, t2);
- }
-
- if (is_right) {
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot);
- } else {
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot);
- }
-
- gen_set_label(shift_label);
- s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
+ gen_shift_flags(s, ot, cpu_T[0], cpu_tmp0, cpu_T[1], is_right);
}
static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2,
int is_right, int is_arith)
{
- int mask;
-
- if (ot == OT_QUAD)
- mask = 0x3f;
- else
- mask = 0x1f;
+ int mask = (ot == OT_QUAD ? 0x3f : 0x1f);
/* load */
if (op1 == OR_TMP0)
@@ -1576,10 +1700,7 @@ static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2,
if (op2 != 0) {
tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4);
tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
- if (is_right)
- s->cc_op = CC_OP_SARB + ot;
- else
- s->cc_op = CC_OP_SHLB + ot;
+ set_cc_op(s, (is_right ? CC_OP_SARB : CC_OP_SHLB) + ot);
}
}
@@ -1591,187 +1712,180 @@ static inline void tcg_gen_lshift(TCGv ret, TCGv arg1, target_long arg2)
tcg_gen_shri_tl(ret, arg1, -arg2);
}
-static void gen_rot_rm_T1(DisasContext *s, int ot, int op1,
- int is_right)
+static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, int is_right)
{
- target_ulong mask;
- int label1, label2, data_bits;
- TCGv t0, t1, t2, a0;
-
- /* XXX: inefficient, but we must use local temps */
- t0 = tcg_temp_local_new();
- t1 = tcg_temp_local_new();
- t2 = tcg_temp_local_new();
- a0 = tcg_temp_local_new();
-
- if (ot == OT_QUAD)
- mask = 0x3f;
- else
- mask = 0x1f;
+ target_ulong mask = (ot == OT_QUAD ? 0x3f : 0x1f);
+ TCGv_i32 t0, t1;
/* load */
if (op1 == OR_TMP0) {
- tcg_gen_mov_tl(a0, cpu_A0);
- gen_op_ld_v(ot + s->mem_index, t0, a0);
+ gen_op_ld_T0_A0(ot + s->mem_index);
} else {
- gen_op_mov_v_reg(ot, t0, op1);
+ gen_op_mov_TN_reg(ot, 0, op1);
}
- tcg_gen_mov_tl(t1, cpu_T[1]);
-
- tcg_gen_andi_tl(t1, t1, mask);
-
- /* Must test zero case to avoid using undefined behaviour in TCG
- shifts. */
- label1 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label1);
-
- if (ot <= OT_WORD)
- tcg_gen_andi_tl(cpu_tmp0, t1, (1 << (3 + ot)) - 1);
- else
- tcg_gen_mov_tl(cpu_tmp0, t1);
-
- gen_extu(ot, t0);
- tcg_gen_mov_tl(t2, t0);
+ tcg_gen_andi_tl(cpu_T[1], cpu_T[1], mask);
- data_bits = 8 << ot;
- /* XXX: rely on behaviour of shifts when operand 2 overflows (XXX:
- fix TCG definition) */
- if (is_right) {
- tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp0);
- tcg_gen_subfi_tl(cpu_tmp0, data_bits, cpu_tmp0);
- tcg_gen_shl_tl(t0, t0, cpu_tmp0);
- } else {
- tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp0);
- tcg_gen_subfi_tl(cpu_tmp0, data_bits, cpu_tmp0);
- tcg_gen_shr_tl(t0, t0, cpu_tmp0);
+ switch (ot) {
+ case OT_BYTE:
+ /* Replicate the 8-bit input so that a 32-bit rotate works. */
+ tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]);
+ tcg_gen_muli_tl(cpu_T[0], cpu_T[0], 0x01010101);
+ goto do_long;
+ case OT_WORD:
+ /* Replicate the 16-bit input so that a 32-bit rotate works. */
+ tcg_gen_deposit_tl(cpu_T[0], cpu_T[0], cpu_T[0], 16, 16);
+ goto do_long;
+ do_long:
+#ifdef TARGET_X86_64
+ case OT_LONG:
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+ tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
+ if (is_right) {
+ tcg_gen_rotr_i32(cpu_tmp2_i32, cpu_tmp2_i32, cpu_tmp3_i32);
+ } else {
+ tcg_gen_rotl_i32(cpu_tmp2_i32, cpu_tmp2_i32, cpu_tmp3_i32);
+ }
+ tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+ break;
+#endif
+ default:
+ if (is_right) {
+ tcg_gen_rotr_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+ } else {
+ tcg_gen_rotl_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+ }
+ break;
}
- tcg_gen_or_tl(t0, t0, cpu_tmp4);
- gen_set_label(label1);
/* store */
if (op1 == OR_TMP0) {
- gen_op_st_v(ot + s->mem_index, t0, a0);
+ gen_op_st_T0_A0(ot + s->mem_index);
} else {
- gen_op_mov_reg_v(ot, op1, t0);
+ gen_op_mov_reg_T0(ot, op1);
}
-
- /* update eflags */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
-
- label2 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label2);
-
- gen_compute_eflags(cpu_cc_src);
- tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C));
- tcg_gen_xor_tl(cpu_tmp0, t2, t0);
- tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1));
- tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O);
- tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0);
+
+ /* We'll need the flags computed into CC_SRC. */
+ gen_compute_eflags(s);
+
+ /* The value that was "rotated out" is now present at the other end
+ of the word. Compute C into CC_DST and O into CC_SRC2. Note that
+ since we've computed the flags into CC_SRC, these variables are
+ currently dead. */
if (is_right) {
- tcg_gen_shri_tl(t0, t0, data_bits - 1);
+ tcg_gen_shri_tl(cpu_cc_src2, cpu_T[0], mask - 1);
+ tcg_gen_shri_tl(cpu_cc_dst, cpu_T[0], mask);
+ } else {
+ tcg_gen_shri_tl(cpu_cc_src2, cpu_T[0], mask);
+ tcg_gen_andi_tl(cpu_cc_dst, cpu_T[0], 1);
}
- tcg_gen_andi_tl(t0, t0, CC_C);
- tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
-
- tcg_gen_discard_tl(cpu_cc_dst);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
-
- gen_set_label(label2);
- s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- tcg_temp_free(a0);
+ tcg_gen_andi_tl(cpu_cc_src2, cpu_cc_src2, 1);
+ tcg_gen_xor_tl(cpu_cc_src2, cpu_cc_src2, cpu_cc_dst);
+
+ /* Now conditionally store the new CC_OP value. If the shift count
+ is 0 we keep the CC_OP_EFLAGS setting so that only CC_SRC is live.
+ Otherwise reuse CC_OP_ADCOX which have the C and O flags split out
+ exactly as we computed above. */
+ t0 = tcg_const_i32(0);
+ t1 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t1, cpu_T[1]);
+ tcg_gen_movi_i32(cpu_tmp2_i32, CC_OP_ADCOX);
+ tcg_gen_movi_i32(cpu_tmp3_i32, CC_OP_EFLAGS);
+ tcg_gen_movcond_i32(TCG_COND_NE, cpu_cc_op, t1, t0,
+ cpu_tmp2_i32, cpu_tmp3_i32);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+
+ /* The CC_OP value is no longer predictable. */
+ set_cc_op(s, CC_OP_DYNAMIC);
}
static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2,
int is_right)
{
- int mask;
- int data_bits;
- TCGv t0, t1, a0;
-
- /* XXX: inefficient, but we must use local temps */
- t0 = tcg_temp_local_new();
- t1 = tcg_temp_local_new();
- a0 = tcg_temp_local_new();
-
- if (ot == OT_QUAD)
- mask = 0x3f;
- else
- mask = 0x1f;
+ int mask = (ot == OT_QUAD ? 0x3f : 0x1f);
+ int shift;
/* load */
if (op1 == OR_TMP0) {
- tcg_gen_mov_tl(a0, cpu_A0);
- gen_op_ld_v(ot + s->mem_index, t0, a0);
+ gen_op_ld_T0_A0(ot + s->mem_index);
} else {
- gen_op_mov_v_reg(ot, t0, op1);
+ gen_op_mov_TN_reg(ot, 0, op1);
}
- gen_extu(ot, t0);
- tcg_gen_mov_tl(t1, t0);
-
op2 &= mask;
- data_bits = 8 << ot;
if (op2 != 0) {
- int shift = op2 & ((1 << (3 + ot)) - 1);
- if (is_right) {
- tcg_gen_shri_tl(cpu_tmp4, t0, shift);
- tcg_gen_shli_tl(t0, t0, data_bits - shift);
- }
- else {
- tcg_gen_shli_tl(cpu_tmp4, t0, shift);
- tcg_gen_shri_tl(t0, t0, data_bits - shift);
+ switch (ot) {
+#ifdef TARGET_X86_64
+ case OT_LONG:
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+ if (is_right) {
+ tcg_gen_rotri_i32(cpu_tmp2_i32, cpu_tmp2_i32, op2);
+ } else {
+ tcg_gen_rotli_i32(cpu_tmp2_i32, cpu_tmp2_i32, op2);
+ }
+ tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+ break;
+#endif
+ default:
+ if (is_right) {
+ tcg_gen_rotri_tl(cpu_T[0], cpu_T[0], op2);
+ } else {
+ tcg_gen_rotli_tl(cpu_T[0], cpu_T[0], op2);
+ }
+ break;
+ case OT_BYTE:
+ mask = 7;
+ goto do_shifts;
+ case OT_WORD:
+ mask = 15;
+ do_shifts:
+ shift = op2 & mask;
+ if (is_right) {
+ shift = mask + 1 - shift;
+ }
+ gen_extu(ot, cpu_T[0]);
+ tcg_gen_shli_tl(cpu_tmp0, cpu_T[0], shift);
+ tcg_gen_shri_tl(cpu_T[0], cpu_T[0], mask + 1 - shift);
+ tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
+ break;
}
- tcg_gen_or_tl(t0, t0, cpu_tmp4);
}
/* store */
if (op1 == OR_TMP0) {
- gen_op_st_v(ot + s->mem_index, t0, a0);
+ gen_op_st_T0_A0(ot + s->mem_index);
} else {
- gen_op_mov_reg_v(ot, op1, t0);
+ gen_op_mov_reg_T0(ot, op1);
}
if (op2 != 0) {
- /* update eflags */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
-
- gen_compute_eflags(cpu_cc_src);
- tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C));
- tcg_gen_xor_tl(cpu_tmp0, t1, t0);
- tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1));
- tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O);
- tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0);
+ /* Compute the flags into CC_SRC. */
+ gen_compute_eflags(s);
+
+ /* The value that was "rotated out" is now present at the other end
+ of the word. Compute C into CC_DST and O into CC_SRC2. Note that
+ since we've computed the flags into CC_SRC, these variables are
+ currently dead. */
if (is_right) {
- tcg_gen_shri_tl(t0, t0, data_bits - 1);
+ tcg_gen_shri_tl(cpu_cc_src2, cpu_T[0], mask - 1);
+ tcg_gen_shri_tl(cpu_cc_dst, cpu_T[0], mask);
+ } else {
+ tcg_gen_shri_tl(cpu_cc_src2, cpu_T[0], mask);
+ tcg_gen_andi_tl(cpu_cc_dst, cpu_T[0], 1);
}
- tcg_gen_andi_tl(t0, t0, CC_C);
- tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
-
- tcg_gen_discard_tl(cpu_cc_dst);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
- s->cc_op = CC_OP_EFLAGS;
+ tcg_gen_andi_tl(cpu_cc_src2, cpu_cc_src2, 1);
+ tcg_gen_xor_tl(cpu_cc_src2, cpu_cc_src2, cpu_cc_dst);
+ set_cc_op(s, CC_OP_ADCOX);
}
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(a0);
}
/* XXX: add faster immediate = 1 case */
static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1,
int is_right)
{
- int label1;
-
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_compute_eflags(s);
+ assert(s->cc_op == CC_OP_EFLAGS);
/* load */
if (op1 == OR_TMP0)
@@ -1781,34 +1895,34 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1,
if (is_right) {
switch (ot) {
- case 0:
+ case OT_BYTE:
gen_helper_rcrb(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
break;
- case 1:
+ case OT_WORD:
gen_helper_rcrw(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
break;
- case 2:
+ case OT_LONG:
gen_helper_rcrl(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
break;
#ifdef TARGET_X86_64
- case 3:
+ case OT_QUAD:
gen_helper_rcrq(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
break;
#endif
}
} else {
switch (ot) {
- case 0:
+ case OT_BYTE:
gen_helper_rclb(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
break;
- case 1:
+ case OT_WORD:
gen_helper_rclw(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
break;
- case 2:
+ case OT_LONG:
gen_helper_rcll(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
break;
#ifdef TARGET_X86_64
- case 3:
+ case OT_QUAD:
gen_helper_rclq(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
break;
#endif
@@ -1819,146 +1933,92 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1,
gen_op_st_T0_A0(ot + s->mem_index);
else
gen_op_mov_reg_T0(ot, op1);
-
- /* update eflags */
- label1 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cc_tmp, -1, label1);
-
- tcg_gen_mov_tl(cpu_cc_src, cpu_cc_tmp);
- tcg_gen_discard_tl(cpu_cc_dst);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
-
- gen_set_label(label1);
- s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
}
/* XXX: add faster immediate case */
-static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1,
- int is_right)
+static void gen_shiftd_rm_T1(DisasContext *s, int ot, int op1,
+ bool is_right, TCGv count_in)
{
- int label1, label2, data_bits;
- target_ulong mask;
- TCGv t0, t1, t2, a0;
-
- t0 = tcg_temp_local_new();
- t1 = tcg_temp_local_new();
- t2 = tcg_temp_local_new();
- a0 = tcg_temp_local_new();
-
- if (ot == OT_QUAD)
- mask = 0x3f;
- else
- mask = 0x1f;
+ target_ulong mask = (ot == OT_QUAD ? 63 : 31);
+ TCGv count;
/* load */
if (op1 == OR_TMP0) {
- tcg_gen_mov_tl(a0, cpu_A0);
- gen_op_ld_v(ot + s->mem_index, t0, a0);
+ gen_op_ld_T0_A0(ot + s->mem_index);
} else {
- gen_op_mov_v_reg(ot, t0, op1);
+ gen_op_mov_TN_reg(ot, 0, op1);
}
- tcg_gen_andi_tl(cpu_T3, cpu_T3, mask);
-
- tcg_gen_mov_tl(t1, cpu_T[1]);
- tcg_gen_mov_tl(t2, cpu_T3);
+ count = tcg_temp_new();
+ tcg_gen_andi_tl(count, count_in, mask);
- /* Must test zero case to avoid using undefined behaviour in TCG
- shifts. */
- label1 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
-
- tcg_gen_addi_tl(cpu_tmp5, t2, -1);
- if (ot == OT_WORD) {
- /* Note: we implement the Intel behaviour for shift count > 16 */
+ switch (ot) {
+ case OT_WORD:
+ /* Note: we implement the Intel behaviour for shift count > 16.
+ This means "shrdw C, B, A" shifts A:B:A >> C. Build the B:A
+ portion by constructing it as a 32-bit value. */
if (is_right) {
- tcg_gen_andi_tl(t0, t0, 0xffff);
- tcg_gen_shli_tl(cpu_tmp0, t1, 16);
- tcg_gen_or_tl(t0, t0, cpu_tmp0);
- tcg_gen_ext32u_tl(t0, t0);
-
- tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5);
-
- /* only needed if count > 16, but a test would complicate */
- tcg_gen_subfi_tl(cpu_tmp5, 32, t2);
- tcg_gen_shl_tl(cpu_tmp0, t0, cpu_tmp5);
-
- tcg_gen_shr_tl(t0, t0, t2);
-
- tcg_gen_or_tl(t0, t0, cpu_tmp0);
+ tcg_gen_deposit_tl(cpu_tmp0, cpu_T[0], cpu_T[1], 16, 16);
+ tcg_gen_mov_tl(cpu_T[1], cpu_T[0]);
+ tcg_gen_mov_tl(cpu_T[0], cpu_tmp0);
} else {
- /* XXX: not optimal */
- tcg_gen_andi_tl(t0, t0, 0xffff);
- tcg_gen_shli_tl(t1, t1, 16);
- tcg_gen_or_tl(t1, t1, t0);
- tcg_gen_ext32u_tl(t1, t1);
-
- tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5);
- tcg_gen_subfi_tl(cpu_tmp0, 32, cpu_tmp5);
- tcg_gen_shr_tl(cpu_tmp5, t1, cpu_tmp0);
- tcg_gen_or_tl(cpu_tmp4, cpu_tmp4, cpu_tmp5);
-
- tcg_gen_shl_tl(t0, t0, t2);
- tcg_gen_subfi_tl(cpu_tmp5, 32, t2);
- tcg_gen_shr_tl(t1, t1, cpu_tmp5);
- tcg_gen_or_tl(t0, t0, t1);
+ tcg_gen_deposit_tl(cpu_T[1], cpu_T[0], cpu_T[1], 16, 16);
}
- } else {
- data_bits = 8 << ot;
+ /* FALLTHRU */
+#ifdef TARGET_X86_64
+ case OT_LONG:
+ /* Concatenate the two 32-bit values and use a 64-bit shift. */
+ tcg_gen_subi_tl(cpu_tmp0, count, 1);
if (is_right) {
- if (ot == OT_LONG)
- tcg_gen_ext32u_tl(t0, t0);
-
- tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5);
+ tcg_gen_concat_tl_i64(cpu_T[0], cpu_T[0], cpu_T[1]);
+ tcg_gen_shr_i64(cpu_tmp0, cpu_T[0], cpu_tmp0);
+ tcg_gen_shr_i64(cpu_T[0], cpu_T[0], count);
+ } else {
+ tcg_gen_concat_tl_i64(cpu_T[0], cpu_T[1], cpu_T[0]);
+ tcg_gen_shl_i64(cpu_tmp0, cpu_T[0], cpu_tmp0);
+ tcg_gen_shl_i64(cpu_T[0], cpu_T[0], count);
+ tcg_gen_shri_i64(cpu_tmp0, cpu_tmp0, 32);
+ tcg_gen_shri_i64(cpu_T[0], cpu_T[0], 32);
+ }
+ break;
+#endif
+ default:
+ tcg_gen_subi_tl(cpu_tmp0, count, 1);
+ if (is_right) {
+ tcg_gen_shr_tl(cpu_tmp0, cpu_T[0], cpu_tmp0);
- tcg_gen_shr_tl(t0, t0, t2);
- tcg_gen_subfi_tl(cpu_tmp5, data_bits, t2);
- tcg_gen_shl_tl(t1, t1, cpu_tmp5);
- tcg_gen_or_tl(t0, t0, t1);
-
+ tcg_gen_subfi_tl(cpu_tmp4, mask + 1, count);
+ tcg_gen_shr_tl(cpu_T[0], cpu_T[0], count);
+ tcg_gen_shl_tl(cpu_T[1], cpu_T[1], cpu_tmp4);
} else {
- if (ot == OT_LONG)
- tcg_gen_ext32u_tl(t1, t1);
-
- tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5);
-
- tcg_gen_shl_tl(t0, t0, t2);
- tcg_gen_subfi_tl(cpu_tmp5, data_bits, t2);
- tcg_gen_shr_tl(t1, t1, cpu_tmp5);
- tcg_gen_or_tl(t0, t0, t1);
+ tcg_gen_shl_tl(cpu_tmp0, cpu_T[0], cpu_tmp0);
+ if (ot == OT_WORD) {
+ /* Only needed if count > 16, for Intel behaviour. */
+ tcg_gen_subfi_tl(cpu_tmp4, 33, count);
+ tcg_gen_shr_tl(cpu_tmp4, cpu_T[1], cpu_tmp4);
+ tcg_gen_or_tl(cpu_tmp0, cpu_tmp0, cpu_tmp4);
+ }
+
+ tcg_gen_subfi_tl(cpu_tmp4, mask + 1, count);
+ tcg_gen_shl_tl(cpu_T[0], cpu_T[0], count);
+ tcg_gen_shr_tl(cpu_T[1], cpu_T[1], cpu_tmp4);
}
+ tcg_gen_movi_tl(cpu_tmp4, 0);
+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_T[1], count, cpu_tmp4,
+ cpu_tmp4, cpu_T[1]);
+ tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+ break;
}
- tcg_gen_mov_tl(t1, cpu_tmp4);
- gen_set_label(label1);
/* store */
if (op1 == OR_TMP0) {
- gen_op_st_v(ot + s->mem_index, t0, a0);
- } else {
- gen_op_mov_reg_v(ot, op1, t0);
- }
-
- /* update eflags */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
-
- label2 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label2);
-
- tcg_gen_mov_tl(cpu_cc_src, t1);
- tcg_gen_mov_tl(cpu_cc_dst, t0);
- if (is_right) {
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot);
+ gen_op_st_T0_A0(ot + s->mem_index);
} else {
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot);
+ gen_op_mov_reg_T0(ot, op1);
}
- gen_set_label(label2);
- s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- tcg_temp_free(a0);
+ gen_shift_flags(s, ot, cpu_T[0], cpu_tmp0, count, is_right);
+ tcg_temp_free(count);
}
static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
@@ -2362,24 +2422,21 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
static inline void gen_jcc(DisasContext *s, int b,
target_ulong val, target_ulong next_eip)
{
- int l1, l2, cc_op;
+ int l1, l2;
- cc_op = s->cc_op;
- gen_update_cc_op(s);
if (s->jmp_opt) {
l1 = gen_new_label();
- gen_jcc1(s, cc_op, b, l1);
-
+ gen_jcc1(s, b, l1);
+
gen_goto_tb(s, 0, next_eip);
gen_set_label(l1);
gen_goto_tb(s, 1, val);
s->is_jmp = DISAS_TB_JUMP;
} else {
-
l1 = gen_new_label();
l2 = gen_new_label();
- gen_jcc1(s, cc_op, b, l1);
+ gen_jcc1(s, b, l1);
gen_jmp_im(next_eip);
tcg_gen_br(l2);
@@ -2391,32 +2448,32 @@ static inline void gen_jcc(DisasContext *s, int b,
}
}
-static void gen_setcc(DisasContext *s, int b)
+static void gen_cmovcc1(CPUX86State *env, DisasContext *s, int ot, int b,
+ int modrm, int reg)
{
- int inv, jcc_op, l1;
- TCGv t0;
+ CCPrepare cc;
- if (is_fast_jcc_case(s, b)) {
- /* nominal case: we use a jump */
- /* XXX: make it faster by adding new instructions in TCG */
- t0 = tcg_temp_local_new();
- tcg_gen_movi_tl(t0, 0);
- l1 = gen_new_label();
- gen_jcc1(s, s->cc_op, b ^ 1, l1);
- tcg_gen_movi_tl(t0, 1);
- gen_set_label(l1);
- tcg_gen_mov_tl(cpu_T[0], t0);
- tcg_temp_free(t0);
- } else {
- /* slow case: it is more efficient not to generate a jump,
- although it is questionnable whether this optimization is
- worth to */
- inv = b & 1;
- jcc_op = (b >> 1) & 7;
- gen_setcc_slow_T0(s, jcc_op);
- if (inv) {
- tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1);
- }
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+
+ cc = gen_prepare_cc(s, b, cpu_T[1]);
+ if (cc.mask != -1) {
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, cc.reg, cc.mask);
+ cc.reg = t0;
+ }
+ if (!cc.use_reg2) {
+ cc.reg2 = tcg_const_tl(cc.imm);
+ }
+
+ tcg_gen_movcond_tl(cc.cond, cpu_T[0], cc.reg, cc.reg2,
+ cpu_T[0], cpu_regs[reg]);
+ gen_op_mov_reg_T0(ot, reg);
+
+ if (cc.mask != -1) {
+ tcg_temp_free(cc.reg);
+ }
+ if (!cc.use_reg2) {
+ tcg_temp_free(cc.reg2);
}
}
@@ -2442,8 +2499,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip)
{
if (s->pe && !s->vm86) {
/* XXX: optimize by finding processor state dynamically */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(cur_eip);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), cpu_tmp2_i32);
@@ -2472,8 +2528,7 @@ gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start,
/* no SVM activated; fast case */
if (likely(!(s->flags & HF_SVMI_MASK)))
return;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_svm_check_intercept_param(cpu_env, tcg_const_i32(type),
tcg_const_i64(param));
@@ -2720,8 +2775,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
{
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(cur_eip);
gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno));
s->is_jmp = DISAS_TB_JUMP;
@@ -2732,8 +2786,7 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
static void gen_interrupt(DisasContext *s, int intno,
target_ulong cur_eip, target_ulong next_eip)
{
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(cur_eip);
gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno),
tcg_const_i32(next_eip - cur_eip));
@@ -2742,8 +2795,7 @@ static void gen_interrupt(DisasContext *s, int intno,
static void gen_debug(DisasContext *s, target_ulong cur_eip)
{
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(cur_eip);
gen_helper_debug(cpu_env);
s->is_jmp = DISAS_TB_JUMP;
@@ -2753,8 +2805,7 @@ static void gen_debug(DisasContext *s, target_ulong cur_eip)
if needed */
static void gen_eob(DisasContext *s)
{
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
gen_helper_reset_inhibit_irq(cpu_env);
}
@@ -2775,8 +2826,9 @@ static void gen_eob(DisasContext *s)
direct call to the next block may occur */
static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
{
+ gen_update_cc_op(s);
+ set_cc_op(s, CC_OP_DYNAMIC);
if (s->jmp_opt) {
- gen_update_cc_op(s);
gen_goto_tb(s, tb_num, eip);
s->is_jmp = DISAS_TB_JUMP;
} else {
@@ -2912,8 +2964,9 @@ static const SSEFunc_0_epp sse_op_table1[256][4] = {
[0xc6] = { (SSEFunc_0_epp)gen_helper_shufps,
(SSEFunc_0_epp)gen_helper_shufpd }, /* XXX: casts */
- [0x38] = { SSE_SPECIAL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* SSSE3/SSE4 */
- [0x3a] = { SSE_SPECIAL, SSE_SPECIAL }, /* SSSE3/SSE4 */
+ /* SSSE3, SSE4, MOVBE, CRC32, BMI1, BMI2, ADX. */
+ [0x38] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },
+ [0x3a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },
/* MMX ops and their SSE extensions */
[0x60] = MMX_OP2(punpcklbw),
@@ -3794,11 +3847,13 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
reg = ((modrm >> 3) & 7) | rex_r;
gen_op_mov_reg_T0(OT_LONG, reg);
break;
+
case 0x138:
- if (s->prefix & PREFIX_REPNZ)
- goto crc32;
case 0x038:
b = modrm;
+ if ((b & 0xf0) == 0xf0) {
+ goto do_0f_38_fx;
+ }
modrm = cpu_ldub_code(env, s->pc++);
rm = modrm & 7;
reg = ((modrm >> 3) & 7) | rex_r;
@@ -3867,39 +3922,418 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
sse_fn_epp(cpu_env, cpu_ptr0, cpu_ptr1);
- if (b == 0x17)
- s->cc_op = CC_OP_EFLAGS;
+ if (b == 0x17) {
+ set_cc_op(s, CC_OP_EFLAGS);
+ }
break;
- case 0x338: /* crc32 */
- crc32:
- b = modrm;
+
+ case 0x238:
+ case 0x338:
+ do_0f_38_fx:
+ /* Various integer extensions at 0f 38 f[0-f]. */
+ b = modrm | (b1 << 8);
modrm = cpu_ldub_code(env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
- if (b != 0xf0 && b != 0xf1)
- goto illegal_op;
- if (!(s->cpuid_ext_features & CPUID_EXT_SSE42))
- goto illegal_op;
+ switch (b) {
+ case 0x3f0: /* crc32 Gd,Eb */
+ case 0x3f1: /* crc32 Gd,Ey */
+ do_crc32:
+ if (!(s->cpuid_ext_features & CPUID_EXT_SSE42)) {
+ goto illegal_op;
+ }
+ if ((b & 0xff) == 0xf0) {
+ ot = OT_BYTE;
+ } else if (s->dflag != 2) {
+ ot = (s->prefix & PREFIX_DATA ? OT_WORD : OT_LONG);
+ } else {
+ ot = OT_QUAD;
+ }
- if (b == 0xf0)
- ot = OT_BYTE;
- else if (b == 0xf1 && s->dflag != 2)
- if (s->prefix & PREFIX_DATA)
- ot = OT_WORD;
- else
- ot = OT_LONG;
- else
- ot = OT_QUAD;
+ gen_op_mov_TN_reg(OT_LONG, 0, reg);
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ gen_helper_crc32(cpu_T[0], cpu_tmp2_i32,
+ cpu_T[0], tcg_const_i32(8 << ot));
- gen_op_mov_TN_reg(OT_LONG, 0, reg);
- tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
- gen_helper_crc32(cpu_T[0], cpu_tmp2_i32,
- cpu_T[0], tcg_const_i32(8 << ot));
+ ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
+ gen_op_mov_reg_T0(ot, reg);
+ break;
- ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
- gen_op_mov_reg_T0(ot, reg);
+ case 0x1f0: /* crc32 or movbe */
+ case 0x1f1:
+ /* For these insns, the f3 prefix is supposed to have priority
+ over the 66 prefix, but that's not what we implement above
+ setting b1. */
+ if (s->prefix & PREFIX_REPNZ) {
+ goto do_crc32;
+ }
+ /* FALLTHRU */
+ case 0x0f0: /* movbe Gy,My */
+ case 0x0f1: /* movbe My,Gy */
+ if (!(s->cpuid_ext_features & CPUID_EXT_MOVBE)) {
+ goto illegal_op;
+ }
+ if (s->dflag != 2) {
+ ot = (s->prefix & PREFIX_DATA ? OT_WORD : OT_LONG);
+ } else {
+ ot = OT_QUAD;
+ }
+
+ /* Load the data incoming to the bswap. Note that the TCG
+ implementation of bswap requires the input be zero
+ extended. In the case of the loads, we simply know that
+ gen_op_ld_v via gen_ldst_modrm does that already. */
+ if ((b & 1) == 0) {
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ } else {
+ switch (ot) {
+ case OT_WORD:
+ tcg_gen_ext16u_tl(cpu_T[0], cpu_regs[reg]);
+ break;
+ default:
+ tcg_gen_ext32u_tl(cpu_T[0], cpu_regs[reg]);
+ break;
+ case OT_QUAD:
+ tcg_gen_mov_tl(cpu_T[0], cpu_regs[reg]);
+ break;
+ }
+ }
+
+ switch (ot) {
+ case OT_WORD:
+ tcg_gen_bswap16_tl(cpu_T[0], cpu_T[0]);
+ break;
+ default:
+ tcg_gen_bswap32_tl(cpu_T[0], cpu_T[0]);
+ break;
+#ifdef TARGET_X86_64
+ case OT_QUAD:
+ tcg_gen_bswap64_tl(cpu_T[0], cpu_T[0]);
+ break;
+#endif
+ }
+
+ if ((b & 1) == 0) {
+ gen_op_mov_reg_T0(ot, reg);
+ } else {
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
+ }
+ break;
+
+ case 0x0f2: /* andn Gy, By, Ey */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)
+ || !(s->prefix & PREFIX_VEX)
+ || s->vex_l != 0) {
+ goto illegal_op;
+ }
+ ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ tcg_gen_andc_tl(cpu_T[0], cpu_regs[s->vex_v], cpu_T[0]);
+ gen_op_mov_reg_T0(ot, reg);
+ gen_op_update1_cc();
+ set_cc_op(s, CC_OP_LOGICB + ot);
+ break;
+
+ case 0x0f7: /* bextr Gy, Ey, By */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)
+ || !(s->prefix & PREFIX_VEX)
+ || s->vex_l != 0) {
+ goto illegal_op;
+ }
+ ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
+ {
+ TCGv bound, zero;
+
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ /* Extract START, and shift the operand.
+ Shifts larger than operand size get zeros. */
+ tcg_gen_ext8u_tl(cpu_A0, cpu_regs[s->vex_v]);
+ tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_A0);
+
+ bound = tcg_const_tl(ot == OT_QUAD ? 63 : 31);
+ zero = tcg_const_tl(0);
+ tcg_gen_movcond_tl(TCG_COND_LEU, cpu_T[0], cpu_A0, bound,
+ cpu_T[0], zero);
+ tcg_temp_free(zero);
+
+ /* Extract the LEN into a mask. Lengths larger than
+ operand size get all ones. */
+ tcg_gen_shri_tl(cpu_A0, cpu_regs[s->vex_v], 8);
+ tcg_gen_ext8u_tl(cpu_A0, cpu_A0);
+ tcg_gen_movcond_tl(TCG_COND_LEU, cpu_A0, cpu_A0, bound,
+ cpu_A0, bound);
+ tcg_temp_free(bound);
+ tcg_gen_movi_tl(cpu_T[1], 1);
+ tcg_gen_shl_tl(cpu_T[1], cpu_T[1], cpu_A0);
+ tcg_gen_subi_tl(cpu_T[1], cpu_T[1], 1);
+ tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+
+ gen_op_mov_reg_T0(ot, reg);
+ gen_op_update1_cc();
+ set_cc_op(s, CC_OP_LOGICB + ot);
+ }
+ break;
+
+ case 0x0f5: /* bzhi Gy, Ey, By */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
+ || !(s->prefix & PREFIX_VEX)
+ || s->vex_l != 0) {
+ goto illegal_op;
+ }
+ ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ tcg_gen_ext8u_tl(cpu_T[1], cpu_regs[s->vex_v]);
+ {
+ TCGv bound = tcg_const_tl(ot == OT_QUAD ? 63 : 31);
+ /* Note that since we're using BMILG (in order to get O
+ cleared) we need to store the inverse into C. */
+ tcg_gen_setcond_tl(TCG_COND_LT, cpu_cc_src,
+ cpu_T[1], bound);
+ tcg_gen_movcond_tl(TCG_COND_GT, cpu_T[1], cpu_T[1],
+ bound, bound, cpu_T[1]);
+ tcg_temp_free(bound);
+ }
+ tcg_gen_movi_tl(cpu_A0, -1);
+ tcg_gen_shl_tl(cpu_A0, cpu_A0, cpu_T[1]);
+ tcg_gen_andc_tl(cpu_T[0], cpu_T[0], cpu_A0);
+ gen_op_mov_reg_T0(ot, reg);
+ gen_op_update1_cc();
+ set_cc_op(s, CC_OP_BMILGB + ot);
+ break;
+
+ case 0x3f6: /* mulx By, Gy, rdx, Ey */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
+ || !(s->prefix & PREFIX_VEX)
+ || s->vex_l != 0) {
+ goto illegal_op;
+ }
+ ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ switch (ot) {
+ TCGv_i64 t0, t1;
+ default:
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+#ifdef TARGET_X86_64
+ tcg_gen_ext32u_i64(t0, cpu_T[0]);
+ tcg_gen_ext32u_i64(t1, cpu_regs[R_EDX]);
+#else
+ tcg_gen_extu_i32_i64(t0, cpu_T[0]);
+ tcg_gen_extu_i32_i64(t0, cpu_regs[R_EDX]);
+#endif
+ tcg_gen_mul_i64(t0, t0, t1);
+ tcg_gen_trunc_i64_tl(cpu_T[0], t0);
+ tcg_gen_shri_i64(t0, t0, 32);
+ tcg_gen_trunc_i64_tl(cpu_T[1], t0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ gen_op_mov_reg_T0(OT_LONG, s->vex_v);
+ gen_op_mov_reg_T1(OT_LONG, reg);
+ break;
+#ifdef TARGET_X86_64
+ case OT_QUAD:
+ tcg_gen_mov_tl(cpu_T[1], cpu_regs[R_EDX]);
+ tcg_gen_mul_tl(cpu_regs[s->vex_v], cpu_T[0], cpu_T[1]);
+ gen_helper_umulh(cpu_regs[reg], cpu_T[0], cpu_T[1]);
+ break;
+#endif
+ }
+ break;
+
+ case 0x3f5: /* pdep Gy, By, Ey */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
+ || !(s->prefix & PREFIX_VEX)
+ || s->vex_l != 0) {
+ goto illegal_op;
+ }
+ ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ /* Note that by zero-extending the mask operand, we
+ automatically handle zero-extending the result. */
+ if (s->dflag == 2) {
+ tcg_gen_mov_tl(cpu_T[1], cpu_regs[s->vex_v]);
+ } else {
+ tcg_gen_ext32u_tl(cpu_T[1], cpu_regs[s->vex_v]);
+ }
+ gen_helper_pdep(cpu_regs[reg], cpu_T[0], cpu_T[1]);
+ break;
+
+ case 0x2f5: /* pext Gy, By, Ey */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
+ || !(s->prefix & PREFIX_VEX)
+ || s->vex_l != 0) {
+ goto illegal_op;
+ }
+ ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ /* Note that by zero-extending the mask operand, we
+ automatically handle zero-extending the result. */
+ if (s->dflag == 2) {
+ tcg_gen_mov_tl(cpu_T[1], cpu_regs[s->vex_v]);
+ } else {
+ tcg_gen_ext32u_tl(cpu_T[1], cpu_regs[s->vex_v]);
+ }
+ gen_helper_pext(cpu_regs[reg], cpu_T[0], cpu_T[1]);
+ break;
+
+ case 0x1f6: /* adcx Gy, Ey */
+ case 0x2f6: /* adox Gy, Ey */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_ADX)) {
+ goto illegal_op;
+ } else {
+ TCGv carry_in, carry_out, zero;
+ int end_op;
+
+ ot = (s->dflag == 2 ? OT_QUAD : OT_LONG);
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+
+ /* Re-use the carry-out from a previous round. */
+ TCGV_UNUSED(carry_in);
+ carry_out = (b == 0x1f6 ? cpu_cc_dst : cpu_cc_src2);
+ switch (s->cc_op) {
+ case CC_OP_ADCX:
+ if (b == 0x1f6) {
+ carry_in = cpu_cc_dst;
+ end_op = CC_OP_ADCX;
+ } else {
+ end_op = CC_OP_ADCOX;
+ }
+ break;
+ case CC_OP_ADOX:
+ if (b == 0x1f6) {
+ end_op = CC_OP_ADCOX;
+ } else {
+ carry_in = cpu_cc_src2;
+ end_op = CC_OP_ADOX;
+ }
+ break;
+ case CC_OP_ADCOX:
+ end_op = CC_OP_ADCOX;
+ carry_in = carry_out;
+ break;
+ default:
+ end_op = (b == 0x1f6 ? CC_OP_ADCX : CC_OP_ADCOX);
+ break;
+ }
+ /* If we can't reuse carry-out, get it out of EFLAGS. */
+ if (TCGV_IS_UNUSED(carry_in)) {
+ if (s->cc_op != CC_OP_ADCX && s->cc_op != CC_OP_ADOX) {
+ gen_compute_eflags(s);
+ }
+ carry_in = cpu_tmp0;
+ tcg_gen_shri_tl(carry_in, cpu_cc_src,
+ ctz32(b == 0x1f6 ? CC_C : CC_O));
+ tcg_gen_andi_tl(carry_in, carry_in, 1);
+ }
+
+ switch (ot) {
+#ifdef TARGET_X86_64
+ case OT_LONG:
+ /* If we know TL is 64-bit, and we want a 32-bit
+ result, just do everything in 64-bit arithmetic. */
+ tcg_gen_ext32u_i64(cpu_regs[reg], cpu_regs[reg]);
+ tcg_gen_ext32u_i64(cpu_T[0], cpu_T[0]);
+ tcg_gen_add_i64(cpu_T[0], cpu_T[0], cpu_regs[reg]);
+ tcg_gen_add_i64(cpu_T[0], cpu_T[0], carry_in);
+ tcg_gen_ext32u_i64(cpu_regs[reg], cpu_T[0]);
+ tcg_gen_shri_i64(carry_out, cpu_T[0], 32);
+ break;
+#endif
+ default:
+ /* Otherwise compute the carry-out in two steps. */
+ zero = tcg_const_tl(0);
+ tcg_gen_add2_tl(cpu_T[0], carry_out,
+ cpu_T[0], zero,
+ carry_in, zero);
+ tcg_gen_add2_tl(cpu_regs[reg], carry_out,
+ cpu_regs[reg], carry_out,
+ cpu_T[0], zero);
+ tcg_temp_free(zero);
+ break;
+ }
+ set_cc_op(s, end_op);
+ }
+ break;
+
+ case 0x1f7: /* shlx Gy, Ey, By */
+ case 0x2f7: /* sarx Gy, Ey, By */
+ case 0x3f7: /* shrx Gy, Ey, By */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
+ || !(s->prefix & PREFIX_VEX)
+ || s->vex_l != 0) {
+ goto illegal_op;
+ }
+ ot = (s->dflag == 2 ? OT_QUAD : OT_LONG);
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ if (ot == OT_QUAD) {
+ tcg_gen_andi_tl(cpu_T[1], cpu_regs[s->vex_v], 63);
+ } else {
+ tcg_gen_andi_tl(cpu_T[1], cpu_regs[s->vex_v], 31);
+ }
+ if (b == 0x1f7) {
+ tcg_gen_shl_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+ } else if (b == 0x2f7) {
+ if (ot != OT_QUAD) {
+ tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
+ }
+ tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+ } else {
+ if (ot != OT_QUAD) {
+ tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]);
+ }
+ tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+ }
+ gen_op_mov_reg_T0(ot, reg);
+ break;
+
+ case 0x0f3:
+ case 0x1f3:
+ case 0x2f3:
+ case 0x3f3: /* Group 17 */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)
+ || !(s->prefix & PREFIX_VEX)
+ || s->vex_l != 0) {
+ goto illegal_op;
+ }
+ ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+
+ switch (reg & 7) {
+ case 1: /* blsr By,Ey */
+ tcg_gen_neg_tl(cpu_T[1], cpu_T[0]);
+ tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+ gen_op_mov_reg_T0(ot, s->vex_v);
+ gen_op_update2_cc();
+ set_cc_op(s, CC_OP_BMILGB + ot);
+ break;
+
+ case 2: /* blsmsk By,Ey */
+ tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
+ tcg_gen_subi_tl(cpu_T[0], cpu_T[0], 1);
+ tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_cc_src);
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+ set_cc_op(s, CC_OP_BMILGB + ot);
+ break;
+
+ case 3: /* blsi By, Ey */
+ tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
+ tcg_gen_subi_tl(cpu_T[0], cpu_T[0], 1);
+ tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_cc_src);
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+ set_cc_op(s, CC_OP_BMILGB + ot);
+ break;
+
+ default:
+ goto illegal_op;
+ }
+ break;
+
+ default:
+ goto illegal_op;
+ }
break;
+
case 0x03a:
case 0x13a:
b = modrm;
@@ -4070,7 +4504,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
val = cpu_ldub_code(env, s->pc++);
if ((b & 0xfc) == 0x60) { /* pcmpXstrX */
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
if (s->dflag == 2)
/* The helper must use entire 64-bit gp registers */
@@ -4081,6 +4515,38 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
sse_fn_eppi(cpu_env, cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
break;
+
+ case 0x33a:
+ /* Various integer extensions at 0f 3a f[0-f]. */
+ b = modrm | (b1 << 8);
+ modrm = cpu_ldub_code(env, s->pc++);
+ reg = ((modrm >> 3) & 7) | rex_r;
+
+ switch (b) {
+ case 0x3f0: /* rorx Gy,Ey, Ib */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
+ || !(s->prefix & PREFIX_VEX)
+ || s->vex_l != 0) {
+ goto illegal_op;
+ }
+ ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ b = cpu_ldub_code(env, s->pc++);
+ if (ot == OT_QUAD) {
+ tcg_gen_rotri_tl(cpu_T[0], cpu_T[0], b & 63);
+ } else {
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+ tcg_gen_rotri_i32(cpu_tmp2_i32, cpu_tmp2_i32, b & 31);
+ tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+ }
+ gen_op_mov_reg_T0(ot, reg);
+ break;
+
+ default:
+ goto illegal_op;
+ }
+ break;
+
default:
goto illegal_op;
}
@@ -4191,7 +4657,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
break;
}
if (b == 0x2e || b == 0x2f) {
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
}
}
}
@@ -4223,47 +4689,49 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
x86_64_hregs = 0;
#endif
s->rip_offset = 0; /* for relative ip address */
+ s->vex_l = 0;
+ s->vex_v = 0;
next_byte:
b = cpu_ldub_code(env, s->pc);
s->pc++;
- /* check prefixes */
+ /* Collect prefixes. */
+ switch (b) {
+ case 0xf3:
+ prefixes |= PREFIX_REPZ;
+ goto next_byte;
+ case 0xf2:
+ prefixes |= PREFIX_REPNZ;
+ goto next_byte;
+ case 0xf0:
+ prefixes |= PREFIX_LOCK;
+ goto next_byte;
+ case 0x2e:
+ s->override = R_CS;
+ goto next_byte;
+ case 0x36:
+ s->override = R_SS;
+ goto next_byte;
+ case 0x3e:
+ s->override = R_DS;
+ goto next_byte;
+ case 0x26:
+ s->override = R_ES;
+ goto next_byte;
+ case 0x64:
+ s->override = R_FS;
+ goto next_byte;
+ case 0x65:
+ s->override = R_GS;
+ goto next_byte;
+ case 0x66:
+ prefixes |= PREFIX_DATA;
+ goto next_byte;
+ case 0x67:
+ prefixes |= PREFIX_ADR;
+ goto next_byte;
#ifdef TARGET_X86_64
- if (CODE64(s)) {
- switch (b) {
- case 0xf3:
- prefixes |= PREFIX_REPZ;
- goto next_byte;
- case 0xf2:
- prefixes |= PREFIX_REPNZ;
- goto next_byte;
- case 0xf0:
- prefixes |= PREFIX_LOCK;
- goto next_byte;
- case 0x2e:
- s->override = R_CS;
- goto next_byte;
- case 0x36:
- s->override = R_SS;
- goto next_byte;
- case 0x3e:
- s->override = R_DS;
- goto next_byte;
- case 0x26:
- s->override = R_ES;
- goto next_byte;
- case 0x64:
- s->override = R_FS;
- goto next_byte;
- case 0x65:
- s->override = R_GS;
- goto next_byte;
- case 0x66:
- prefixes |= PREFIX_DATA;
- goto next_byte;
- case 0x67:
- prefixes |= PREFIX_ADR;
- goto next_byte;
- case 0x40 ... 0x4f:
+ case 0x40 ... 0x4f:
+ if (CODE64(s)) {
/* REX prefix */
rex_w = (b >> 3) & 1;
rex_r = (b & 0x4) << 1;
@@ -4272,58 +4740,85 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
x86_64_hregs = 1; /* select uniform byte register addressing */
goto next_byte;
}
+ break;
+#endif
+ case 0xc5: /* 2-byte VEX */
+ case 0xc4: /* 3-byte VEX */
+ /* VEX prefixes cannot be used except in 32-bit mode.
+ Otherwise the instruction is LES or LDS. */
+ if (s->code32 && !s->vm86) {
+ static const int pp_prefix[4] = {
+ 0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ
+ };
+ int vex3, vex2 = cpu_ldub_code(env, s->pc);
+
+ if (!CODE64(s) && (vex2 & 0xc0) != 0xc0) {
+ /* 4.1.4.6: In 32-bit mode, bits [7:6] must be 11b,
+ otherwise the instruction is LES or LDS. */
+ break;
+ }
+ s->pc++;
+
+ /* 4.1.1-4.1.3: No preceeding lock, 66, f2, f3, or rex prefixes. */
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ
+ | PREFIX_LOCK | PREFIX_DATA)) {
+ goto illegal_op;
+ }
+#ifdef TARGET_X86_64
+ if (x86_64_hregs) {
+ goto illegal_op;
+ }
+#endif
+ rex_r = (~vex2 >> 4) & 8;
+ if (b == 0xc5) {
+ vex3 = vex2;
+ b = cpu_ldub_code(env, s->pc++);
+ } else {
+#ifdef TARGET_X86_64
+ s->rex_x = (~vex2 >> 3) & 8;
+ s->rex_b = (~vex2 >> 2) & 8;
+#endif
+ vex3 = cpu_ldub_code(env, s->pc++);
+ rex_w = (vex3 >> 7) & 1;
+ switch (vex2 & 0x1f) {
+ case 0x01: /* Implied 0f leading opcode bytes. */
+ b = cpu_ldub_code(env, s->pc++) | 0x100;
+ break;
+ case 0x02: /* Implied 0f 38 leading opcode bytes. */
+ b = 0x138;
+ break;
+ case 0x03: /* Implied 0f 3a leading opcode bytes. */
+ b = 0x13a;
+ break;
+ default: /* Reserved for future use. */
+ goto illegal_op;
+ }
+ }
+ s->vex_v = (~vex3 >> 3) & 0xf;
+ s->vex_l = (vex3 >> 2) & 1;
+ prefixes |= pp_prefix[vex3 & 3] | PREFIX_VEX;
+ }
+ break;
+ }
+
+ /* Post-process prefixes. */
+ if (prefixes & PREFIX_DATA) {
+ dflag ^= 1;
+ }
+ if (prefixes & PREFIX_ADR) {
+ aflag ^= 1;
+ }
+#ifdef TARGET_X86_64
+ if (CODE64(s)) {
if (rex_w == 1) {
/* 0x66 is ignored if rex.w is set */
dflag = 2;
- } else {
- if (prefixes & PREFIX_DATA)
- dflag ^= 1;
}
- if (!(prefixes & PREFIX_ADR))
+ if (!(prefixes & PREFIX_ADR)) {
aflag = 2;
- } else
-#endif
- {
- switch (b) {
- case 0xf3:
- prefixes |= PREFIX_REPZ;
- goto next_byte;
- case 0xf2:
- prefixes |= PREFIX_REPNZ;
- goto next_byte;
- case 0xf0:
- prefixes |= PREFIX_LOCK;
- goto next_byte;
- case 0x2e:
- s->override = R_CS;
- goto next_byte;
- case 0x36:
- s->override = R_SS;
- goto next_byte;
- case 0x3e:
- s->override = R_DS;
- goto next_byte;
- case 0x26:
- s->override = R_ES;
- goto next_byte;
- case 0x64:
- s->override = R_FS;
- goto next_byte;
- case 0x65:
- s->override = R_GS;
- goto next_byte;
- case 0x66:
- prefixes |= PREFIX_DATA;
- goto next_byte;
- case 0x67:
- prefixes |= PREFIX_ADR;
- goto next_byte;
}
- if (prefixes & PREFIX_DATA)
- dflag ^= 1;
- if (prefixes & PREFIX_ADR)
- aflag ^= 1;
}
+#endif
s->prefix = prefixes;
s->aflag = aflag;
@@ -4374,10 +4869,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} else if (op == OP_XORL && rm == reg) {
xor_zero:
/* xor reg, reg optimisation */
+ set_cc_op(s, CC_OP_CLR);
gen_op_movl_T0_0();
- s->cc_op = CC_OP_LOGICB + ot;
gen_op_mov_reg_T0(ot, reg);
- gen_op_update1_cc();
break;
} else {
opreg = rm;
@@ -4490,7 +4984,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
val = insn_get(env, s, ot);
gen_op_movl_T1_im(val);
gen_op_testl_T0_T1_cc();
- s->cc_op = CC_OP_LOGICB + ot;
+ set_cc_op(s, CC_OP_LOGICB + ot);
break;
case 2: /* not */
tcg_gen_not_tl(cpu_T[0], cpu_T[0]);
@@ -4508,7 +5002,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_mov_reg_T0(ot, rm);
}
gen_op_update_neg_cc();
- s->cc_op = CC_OP_SUBB + ot;
+ set_cc_op(s, CC_OP_SUBB + ot);
break;
case 4: /* mul */
switch(ot) {
@@ -4521,7 +5015,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_mov_reg_T0(OT_WORD, R_EAX);
tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
tcg_gen_andi_tl(cpu_cc_src, cpu_T[0], 0xff00);
- s->cc_op = CC_OP_MULB;
+ set_cc_op(s, CC_OP_MULB);
break;
case OT_WORD:
gen_op_mov_TN_reg(OT_WORD, 1, R_EAX);
@@ -4534,7 +5028,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16);
gen_op_mov_reg_T0(OT_WORD, R_EDX);
tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
- s->cc_op = CC_OP_MULW;
+ set_cc_op(s, CC_OP_MULW);
break;
default:
case OT_LONG:
@@ -4566,12 +5060,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
}
#endif
- s->cc_op = CC_OP_MULL;
+ set_cc_op(s, CC_OP_MULL);
break;
#ifdef TARGET_X86_64
case OT_QUAD:
gen_helper_mulq_EAX_T0(cpu_env, cpu_T[0]);
- s->cc_op = CC_OP_MULQ;
+ set_cc_op(s, CC_OP_MULQ);
break;
#endif
}
@@ -4588,7 +5082,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
tcg_gen_ext8s_tl(cpu_tmp0, cpu_T[0]);
tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
- s->cc_op = CC_OP_MULB;
+ set_cc_op(s, CC_OP_MULB);
break;
case OT_WORD:
gen_op_mov_TN_reg(OT_WORD, 1, R_EAX);
@@ -4602,7 +5096,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16);
gen_op_mov_reg_T0(OT_WORD, R_EDX);
- s->cc_op = CC_OP_MULW;
+ set_cc_op(s, CC_OP_MULW);
break;
default:
case OT_LONG:
@@ -4636,12 +5130,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
}
#endif
- s->cc_op = CC_OP_MULL;
+ set_cc_op(s, CC_OP_MULL);
break;
#ifdef TARGET_X86_64
case OT_QUAD:
gen_helper_imulq_EAX_T0(cpu_env, cpu_T[0]);
- s->cc_op = CC_OP_MULQ;
+ set_cc_op(s, CC_OP_MULQ);
break;
#endif
}
@@ -4761,8 +5255,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_ldu_T0_A0(OT_WORD + s->mem_index);
do_lcall:
if (s->pe && !s->vm86) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
gen_helper_lcall_protected(cpu_env, cpu_tmp2_i32, cpu_T[1],
@@ -4788,8 +5281,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_ldu_T0_A0(OT_WORD + s->mem_index);
do_ljmp:
if (s->pe && !s->vm86) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
gen_helper_ljmp_protected(cpu_env, cpu_tmp2_i32, cpu_T[1],
@@ -4822,7 +5314,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
gen_op_mov_TN_reg(ot, 1, reg);
gen_op_testl_T0_T1_cc();
- s->cc_op = CC_OP_LOGICB + ot;
+ set_cc_op(s, CC_OP_LOGICB + ot);
break;
case 0xa8: /* test eAX, Iv */
@@ -4836,7 +5328,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_mov_TN_reg(ot, 0, OR_EAX);
gen_op_movl_T1_im(val);
gen_op_testl_T0_T1_cc();
- s->cc_op = CC_OP_LOGICB + ot;
+ set_cc_op(s, CC_OP_LOGICB + ot);
break;
case 0x98: /* CWDE/CBW */
@@ -4937,7 +5429,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
}
gen_op_mov_reg_T0(ot, reg);
- s->cc_op = CC_OP_MULB + ot;
+ set_cc_op(s, CC_OP_MULB + ot);
break;
case 0x1c0:
case 0x1c1: /* xadd Ev, Gv */
@@ -4964,7 +5456,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_mov_reg_T1(ot, reg);
}
gen_op_update2_cc();
- s->cc_op = CC_OP_ADDB + ot;
+ set_cc_op(s, CC_OP_ADDB + ot);
break;
case 0x1b0:
case 0x1b1: /* cmpxchg Ev, Gv */
@@ -4994,9 +5486,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
rm = 0; /* avoid warning */
}
label1 = gen_new_label();
- tcg_gen_sub_tl(t2, cpu_regs[R_EAX], t0);
+ tcg_gen_mov_tl(t2, cpu_regs[R_EAX]);
+ gen_extu(ot, t0);
gen_extu(ot, t2);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
+ tcg_gen_brcond_tl(TCG_COND_EQ, t2, t0, label1);
label2 = gen_new_label();
if (mod == 3) {
gen_op_mov_reg_v(ot, R_EAX, t0);
@@ -5015,8 +5508,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
gen_set_label(label2);
tcg_gen_mov_tl(cpu_cc_src, t0);
- tcg_gen_mov_tl(cpu_cc_dst, t2);
- s->cc_op = CC_OP_SUBB + ot;
+ tcg_gen_mov_tl(cpu_cc_srcT, t2);
+ tcg_gen_sub_tl(cpu_cc_dst, t2, t0);
+ set_cc_op(s, CC_OP_SUBB + ot);
tcg_temp_free(t0);
tcg_temp_free(t1);
tcg_temp_free(t2);
@@ -5033,8 +5527,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (!(s->cpuid_ext_features & CPUID_EXT_CX16))
goto illegal_op;
gen_jmp_im(pc_start - s->cs_base);
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_lea_modrm(env, s, modrm, &reg_addr, &offset_addr);
gen_helper_cmpxchg16b(cpu_env, cpu_A0);
} else
@@ -5043,12 +5536,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (!(s->cpuid_features & CPUID_CX8))
goto illegal_op;
gen_jmp_im(pc_start - s->cs_base);
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_lea_modrm(env, s, modrm, &reg_addr, &offset_addr);
gen_helper_cmpxchg8b(cpu_env, cpu_A0);
}
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
/**************************/
@@ -5452,13 +5944,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
break;
case 0xc4: /* les Gv */
- if (CODE64(s))
- goto illegal_op;
+ /* In CODE64 this is VEX3; see above. */
op = R_ES;
goto do_lxx;
case 0xc5: /* lds Gv */
- if (CODE64(s))
- goto illegal_op;
+ /* In CODE64 this is VEX2; see above. */
op = R_DS;
goto do_lxx;
case 0x1b2: /* lss Gv */
@@ -5569,12 +6059,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_mov_TN_reg(ot, 1, reg);
if (shift) {
- val = cpu_ldub_code(env, s->pc++);
- tcg_gen_movi_tl(cpu_T3, val);
+ TCGv imm = tcg_const_tl(cpu_ldub_code(env, s->pc++));
+ gen_shiftd_rm_T1(s, ot, opreg, op, imm);
+ tcg_temp_free(imm);
} else {
- tcg_gen_mov_tl(cpu_T3, cpu_regs[R_ECX]);
+ gen_shiftd_rm_T1(s, ot, opreg, op, cpu_regs[R_ECX]);
}
- gen_shiftd_rm_T1_T3(s, ot, opreg, op);
break;
/************************/
@@ -5717,8 +6207,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
break;
case 0x0c: /* fldenv mem */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fldenv(cpu_env, cpu_A0, tcg_const_i32(s->dflag));
break;
@@ -5728,8 +6217,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fldcw(cpu_env, cpu_tmp2_i32);
break;
case 0x0e: /* fnstenv mem */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fstenv(cpu_env, cpu_A0, tcg_const_i32(s->dflag));
break;
@@ -5739,27 +6227,23 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_st_T0_A0(OT_WORD + s->mem_index);
break;
case 0x1d: /* fldt mem */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fldt_ST0(cpu_env, cpu_A0);
break;
case 0x1f: /* fstpt mem */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fstt_ST0(cpu_env, cpu_A0);
gen_helper_fpop(cpu_env);
break;
case 0x2c: /* frstor mem */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_frstor(cpu_env, cpu_A0, tcg_const_i32(s->dflag));
break;
case 0x2e: /* fnsave mem */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fsave(cpu_env, cpu_A0, tcg_const_i32(s->dflag));
break;
@@ -5769,14 +6253,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_st_T0_A0(OT_WORD + s->mem_index);
break;
case 0x3c: /* fbld */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fbld_ST0(cpu_env, cpu_A0);
break;
case 0x3e: /* fbstp */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fbst_ST0(cpu_env, cpu_A0);
gen_helper_fpop(cpu_env);
@@ -5814,8 +6296,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
switch(rm) {
case 0: /* fnop */
/* check exceptions (FreeBSD FPU probe) */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fwait(cpu_env);
break;
@@ -5996,18 +6477,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
break;
case 0x1d: /* fucomi */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
gen_helper_fucomi_ST0_FT0(cpu_env);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x1e: /* fcomi */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
gen_helper_fcomi_ST0_FT0(cpu_env);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x28: /* ffree sti */
gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg));
@@ -6059,20 +6538,18 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
break;
case 0x3d: /* fucomip */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
gen_helper_fucomi_ST0_FT0(cpu_env);
gen_helper_fpop(cpu_env);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x3e: /* fcomip */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
gen_helper_fcomi_ST0_FT0(cpu_env);
gen_helper_fpop(cpu_env);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x10 ... 0x13: /* fcmovxx */
case 0x18 ... 0x1b:
@@ -6086,7 +6563,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
};
op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1);
l1 = gen_new_label();
- gen_jcc1(s, s->cc_op, op1, l1);
+ gen_jcc1_noeob(s, op1, l1);
gen_helper_fmov_ST0_STN(cpu_env, tcg_const_i32(opreg));
gen_set_label(l1);
}
@@ -6150,7 +6627,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
} else {
gen_scas(s, ot);
- s->cc_op = CC_OP_SUBB + ot;
}
break;
@@ -6166,7 +6642,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
} else {
gen_cmps(s, ot);
- s->cc_op = CC_OP_SUBB + ot;
}
break;
case 0x6c: /* insS */
@@ -6323,8 +6798,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
s->pc += 2;
do_lret:
if (s->pe && !s->vm86) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_lret_protected(cpu_env, tcg_const_i32(s->dflag),
tcg_const_i32(val));
@@ -6354,21 +6828,20 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (!s->pe) {
/* real mode */
gen_helper_iret_real(cpu_env, tcg_const_i32(s->dflag));
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
} else if (s->vm86) {
if (s->iopl != 3) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
gen_helper_iret_real(cpu_env, tcg_const_i32(s->dflag));
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
}
} else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_iret_protected(cpu_env, tcg_const_i32(s->dflag),
tcg_const_i32(s->pc - s->cs_base));
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
}
gen_eob(s);
break;
@@ -6455,44 +6928,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 0x190 ... 0x19f: /* setcc Gv */
modrm = cpu_ldub_code(env, s->pc++);
- gen_setcc(s, b);
+ gen_setcc1(s, b, cpu_T[0]);
gen_ldst_modrm(env, s, modrm, OT_BYTE, OR_TMP0, 1);
break;
case 0x140 ... 0x14f: /* cmov Gv, Ev */
- {
- int l1;
- TCGv t0;
-
- ot = dflag + OT_WORD;
- modrm = cpu_ldub_code(env, s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- t0 = tcg_temp_local_new();
- if (mod != 3) {
- gen_lea_modrm(env, s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_v(ot + s->mem_index, t0, cpu_A0);
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_mov_v_reg(ot, t0, rm);
- }
-#ifdef TARGET_X86_64
- if (ot == OT_LONG) {
- /* XXX: specific Intel behaviour ? */
- l1 = gen_new_label();
- gen_jcc1(s, s->cc_op, b ^ 1, l1);
- tcg_gen_mov_tl(cpu_regs[reg], t0);
- gen_set_label(l1);
- tcg_gen_ext32u_tl(cpu_regs[reg], cpu_regs[reg]);
- } else
-#endif
- {
- l1 = gen_new_label();
- gen_jcc1(s, s->cc_op, b ^ 1, l1);
- gen_op_mov_reg_v(ot, reg, t0);
- gen_set_label(l1);
- }
- tcg_temp_free(t0);
- }
+ ot = dflag + OT_WORD;
+ modrm = cpu_ldub_code(env, s->pc++);
+ reg = ((modrm >> 3) & 7) | rex_r;
+ gen_cmovcc1(env, s, ot, b, modrm, reg);
break;
/************************/
@@ -6502,8 +6945,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (s->vm86 && s->iopl != 3) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_helper_read_eflags(cpu_T[0], cpu_env);
gen_push_T0(s);
}
@@ -6560,7 +7002,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
}
gen_pop_update(s);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
/* abort translation because TF/AC flag may change */
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
@@ -6570,44 +7012,30 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM))
goto illegal_op;
gen_op_mov_TN_reg(OT_BYTE, 0, R_AH);
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_compute_eflags(cpu_cc_src);
+ gen_compute_eflags(s);
tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O);
tcg_gen_andi_tl(cpu_T[0], cpu_T[0], CC_S | CC_Z | CC_A | CC_P | CC_C);
tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_T[0]);
- s->cc_op = CC_OP_EFLAGS;
break;
case 0x9f: /* lahf */
if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM))
goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_compute_eflags(cpu_T[0]);
+ gen_compute_eflags(s);
/* Note: gen_compute_eflags() only gives the condition codes */
- tcg_gen_ori_tl(cpu_T[0], cpu_T[0], 0x02);
+ tcg_gen_ori_tl(cpu_T[0], cpu_cc_src, 0x02);
gen_op_mov_reg_T0(OT_BYTE, R_AH);
break;
case 0xf5: /* cmc */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_compute_eflags(cpu_cc_src);
+ gen_compute_eflags(s);
tcg_gen_xori_tl(cpu_cc_src, cpu_cc_src, CC_C);
- s->cc_op = CC_OP_EFLAGS;
break;
case 0xf8: /* clc */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_compute_eflags(cpu_cc_src);
+ gen_compute_eflags(s);
tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_C);
- s->cc_op = CC_OP_EFLAGS;
break;
case 0xf9: /* stc */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_compute_eflags(cpu_cc_src);
+ gen_compute_eflags(s);
tcg_gen_ori_tl(cpu_cc_src, cpu_cc_src, CC_C);
- s->cc_op = CC_OP_EFLAGS;
break;
case 0xfc: /* cld */
tcg_gen_movi_i32(cpu_tmp2_i32, 1);
@@ -6697,7 +7125,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
break;
}
- s->cc_op = CC_OP_SARB + ot;
+ set_cc_op(s, CC_OP_SARB + ot);
if (op != 0) {
if (mod != 3)
gen_op_st_T0_A0(ot + s->mem_index);
@@ -6707,81 +7135,88 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_movi_tl(cpu_cc_dst, 0);
}
break;
- case 0x1bc: /* bsf */
- case 0x1bd: /* bsr */
- {
- int label1;
- TCGv t0;
-
- ot = dflag + OT_WORD;
- modrm = cpu_ldub_code(env, s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- gen_ldst_modrm(env, s,modrm, ot, OR_TMP0, 0);
- gen_extu(ot, cpu_T[0]);
- t0 = tcg_temp_local_new();
- tcg_gen_mov_tl(t0, cpu_T[0]);
- if ((b & 1) && (prefixes & PREFIX_REPZ) &&
- (s->cpuid_ext3_features & CPUID_EXT3_ABM)) {
- switch(ot) {
- case OT_WORD: gen_helper_lzcnt(cpu_T[0], t0,
- tcg_const_i32(16)); break;
- case OT_LONG: gen_helper_lzcnt(cpu_T[0], t0,
- tcg_const_i32(32)); break;
- case OT_QUAD: gen_helper_lzcnt(cpu_T[0], t0,
- tcg_const_i32(64)); break;
- }
- gen_op_mov_reg_T0(ot, reg);
+ case 0x1bc: /* bsf / tzcnt */
+ case 0x1bd: /* bsr / lzcnt */
+ ot = dflag + OT_WORD;
+ modrm = cpu_ldub_code(env, s->pc++);
+ reg = ((modrm >> 3) & 7) | rex_r;
+ gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
+ gen_extu(ot, cpu_T[0]);
+
+ /* Note that lzcnt and tzcnt are in different extensions. */
+ if ((prefixes & PREFIX_REPZ)
+ && (b & 1
+ ? s->cpuid_ext3_features & CPUID_EXT3_ABM
+ : s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)) {
+ int size = 8 << ot;
+ tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
+ if (b & 1) {
+ /* For lzcnt, reduce the target_ulong result by the
+ number of zeros that we expect to find at the top. */
+ gen_helper_clz(cpu_T[0], cpu_T[0]);
+ tcg_gen_subi_tl(cpu_T[0], cpu_T[0], TARGET_LONG_BITS - size);
} else {
- label1 = gen_new_label();
- tcg_gen_movi_tl(cpu_cc_dst, 0);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, label1);
- if (b & 1) {
- gen_helper_bsr(cpu_T[0], t0);
- } else {
- gen_helper_bsf(cpu_T[0], t0);
- }
- gen_op_mov_reg_T0(ot, reg);
- tcg_gen_movi_tl(cpu_cc_dst, 1);
- gen_set_label(label1);
- tcg_gen_discard_tl(cpu_cc_src);
- s->cc_op = CC_OP_LOGICB + ot;
+ /* For tzcnt, a zero input must return the operand size:
+ force all bits outside the operand size to 1. */
+ target_ulong mask = (target_ulong)-2 << (size - 1);
+ tcg_gen_ori_tl(cpu_T[0], cpu_T[0], mask);
+ gen_helper_ctz(cpu_T[0], cpu_T[0]);
}
- tcg_temp_free(t0);
+ /* For lzcnt/tzcnt, C and Z bits are defined and are
+ related to the result. */
+ gen_op_update1_cc();
+ set_cc_op(s, CC_OP_BMILGB + ot);
+ } else {
+ /* For bsr/bsf, only the Z bit is defined and it is related
+ to the input and not the result. */
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+ set_cc_op(s, CC_OP_LOGICB + ot);
+ if (b & 1) {
+ /* For bsr, return the bit index of the first 1 bit,
+ not the count of leading zeros. */
+ gen_helper_clz(cpu_T[0], cpu_T[0]);
+ tcg_gen_xori_tl(cpu_T[0], cpu_T[0], TARGET_LONG_BITS - 1);
+ } else {
+ gen_helper_ctz(cpu_T[0], cpu_T[0]);
+ }
+ /* ??? The manual says that the output is undefined when the
+ input is zero, but real hardware leaves it unchanged, and
+ real programs appear to depend on that. */
+ tcg_gen_movi_tl(cpu_tmp0, 0);
+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_T[0], cpu_cc_dst, cpu_tmp0,
+ cpu_regs[reg], cpu_T[0]);
}
+ gen_op_mov_reg_T0(ot, reg);
break;
/************************/
/* bcd */
case 0x27: /* daa */
if (CODE64(s))
goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_helper_daa(cpu_env);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x2f: /* das */
if (CODE64(s))
goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_helper_das(cpu_env);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x37: /* aaa */
if (CODE64(s))
goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_helper_aaa(cpu_env);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x3f: /* aas */
if (CODE64(s))
goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_helper_aas(cpu_env);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
case 0xd4: /* aam */
if (CODE64(s))
@@ -6791,7 +7226,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base);
} else {
gen_helper_aam(cpu_env, tcg_const_i32(val));
- s->cc_op = CC_OP_LOGICB;
+ set_cc_op(s, CC_OP_LOGICB);
}
break;
case 0xd5: /* aad */
@@ -6799,7 +7234,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
goto illegal_op;
val = cpu_ldub_code(env, s->pc++);
gen_helper_aad(cpu_env, tcg_const_i32(val));
- s->cc_op = CC_OP_LOGICB;
+ set_cc_op(s, CC_OP_LOGICB);
break;
/************************/
/* misc */
@@ -6821,8 +7256,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
(HF_MP_MASK | HF_TS_MASK)) {
gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
} else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fwait(cpu_env);
}
@@ -6841,8 +7275,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 0xce: /* into */
if (CODE64(s))
goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_into(cpu_env, tcg_const_i32(s->pc - pc_start));
break;
@@ -6935,9 +7368,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 0xd6: /* salc */
if (CODE64(s))
goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_compute_eflags_c(cpu_T[0]);
+ gen_compute_eflags_c(s, cpu_T[0]);
tcg_gen_neg_tl(cpu_T[0], cpu_T[0]);
gen_op_mov_reg_T0(OT_BYTE, R_EAX);
break;
@@ -6961,17 +7392,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
switch(b) {
case 0: /* loopnz */
case 1: /* loopz */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
gen_op_add_reg_im(s->aflag, R_ECX, -1);
gen_op_jz_ecx(s->aflag, l3);
- gen_compute_eflags(cpu_tmp0);
- tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_Z);
- if (b == 0) {
- tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1);
- } else {
- tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, l1);
- }
+ gen_jcc1(s, (JCC_Z << 1) | (b ^ 1), l1);
break;
case 2: /* loop */
gen_op_add_reg_im(s->aflag, R_ECX, -1);
@@ -6998,8 +7421,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
if (b & 2) {
gen_helper_rdmsr(cpu_env);
@@ -7009,8 +7431,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
break;
case 0x131: /* rdtsc */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
if (use_icount)
gen_io_start();
@@ -7021,8 +7442,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
break;
case 0x133: /* rdpmc */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_rdpmc(cpu_env);
break;
@@ -7068,15 +7488,15 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_jmp_im(pc_start - s->cs_base);
gen_helper_sysret(cpu_env, tcg_const_i32(s->dflag));
/* condition codes are modified only in long mode */
- if (s->lma)
- s->cc_op = CC_OP_EFLAGS;
+ if (s->lma) {
+ set_cc_op(s, CC_OP_EFLAGS);
+ }
gen_eob(s);
}
break;
#endif
case 0x1a2: /* cpuid */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_cpuid(cpu_env);
break;
@@ -7084,8 +7504,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
s->is_jmp = DISAS_TB_JUMP;
@@ -7147,14 +7566,13 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (!s->pe || s->vm86)
goto illegal_op;
gen_ldst_modrm(env, s, modrm, OT_WORD, OR_TMP0, 0);
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
if (op == 4) {
gen_helper_verr(cpu_env, cpu_T[0]);
} else {
gen_helper_verw(cpu_env, cpu_T[0]);
}
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
default:
goto illegal_op;
@@ -7186,8 +7604,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
s->cpl != 0)
goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
#ifdef TARGET_X86_64
if (s->aflag == 2) {
@@ -7247,8 +7664,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 2: /* lgdt */
case 3: /* lidt */
if (mod == 3) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
switch(rm) {
case 0: /* VMRUN */
@@ -7376,8 +7792,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_lea_modrm(env, s, modrm, &reg_addr, &offset_addr);
gen_helper_invlpg(cpu_env, cpu_A0);
@@ -7410,8 +7825,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 1: /* rdtscp */
if (!(s->cpuid_ext2_features & CPUID_EXT2_RDTSCP))
goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
if (use_icount)
gen_io_start();
@@ -7507,12 +7921,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} else {
gen_op_mov_reg_v(ot, rm, t0);
}
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_compute_eflags(cpu_cc_src);
+ gen_compute_eflags(s);
tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_Z);
tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t2);
- s->cc_op = CC_OP_EFLAGS;
tcg_temp_free(t0);
tcg_temp_free(t1);
tcg_temp_free(t2);
@@ -7530,8 +7941,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
reg = ((modrm >> 3) & 7) | rex_r;
gen_ldst_modrm(env, s, modrm, OT_WORD, OR_TMP0, 0);
t0 = tcg_temp_local_new();
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
if (b == 0x102) {
gen_helper_lar(t0, cpu_env, cpu_T[0]);
} else {
@@ -7542,7 +7952,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1);
gen_op_mov_reg_v(ot, reg, t0);
gen_set_label(label1);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
tcg_temp_free(t0);
}
break;
@@ -7596,8 +8006,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 3:
case 4:
case 8:
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
if (b & 2) {
gen_op_mov_TN_reg(ot, 0, rm);
@@ -7686,8 +8095,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
break;
}
gen_lea_modrm(env, s, modrm, &reg_addr, &offset_addr);
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fxsave(cpu_env, cpu_A0, tcg_const_i32((s->dflag == 2)));
break;
@@ -7700,8 +8108,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
break;
}
gen_lea_modrm(env, s, modrm, &reg_addr, &offset_addr);
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
+ gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_fxrstor(cpu_env, cpu_A0,
tcg_const_i32((s->dflag == 2)));
@@ -7785,7 +8192,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_popcnt(cpu_T[0], cpu_env, cpu_T[0], tcg_const_i32(ot));
gen_op_mov_reg_T0(ot, reg);
- s->cc_op = CC_OP_EFLAGS;
+ set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x10e ... 0x10f:
/* 3DNow! instructions, ignore prefixes */
@@ -7820,12 +8227,12 @@ void optimize_flags_init(void)
cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
cpu_cc_op = tcg_global_mem_new_i32(TCG_AREG0,
offsetof(CPUX86State, cc_op), "cc_op");
- cpu_cc_src = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_src),
- "cc_src");
cpu_cc_dst = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_dst),
"cc_dst");
- cpu_cc_tmp = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_tmp),
- "cc_tmp");
+ cpu_cc_src = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_src),
+ "cc_src");
+ cpu_cc_src2 = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_src2),
+ "cc_src2");
#ifdef TARGET_X86_64
cpu_regs[R_EAX] = tcg_global_mem_new_i64(TCG_AREG0,
@@ -7918,6 +8325,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env,
dc->tf = (flags >> TF_SHIFT) & 1;
dc->singlestep_enabled = env->singlestep_enabled;
dc->cc_op = CC_OP_DYNAMIC;
+ dc->cc_op_dirty = false;
dc->cs_base = cs_base;
dc->tb = tb;
dc->popl_esp_hack = 0;
@@ -7951,16 +8359,15 @@ static inline void gen_intermediate_code_internal(CPUX86State *env,
cpu_T[0] = tcg_temp_new();
cpu_T[1] = tcg_temp_new();
cpu_A0 = tcg_temp_new();
- cpu_T3 = tcg_temp_new();
cpu_tmp0 = tcg_temp_new();
cpu_tmp1_i64 = tcg_temp_new_i64();
cpu_tmp2_i32 = tcg_temp_new_i32();
cpu_tmp3_i32 = tcg_temp_new_i32();
cpu_tmp4 = tcg_temp_new();
- cpu_tmp5 = tcg_temp_new();
cpu_ptr0 = tcg_temp_new_ptr();
cpu_ptr1 = tcg_temp_new_ptr();
+ cpu_cc_srcT = tcg_temp_local_new();
gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index 6b87340174..ccaf838afa 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -1012,8 +1012,6 @@ static void gen_intermediate_code_internal(CPULM32State *env,
int num_insns;
int max_insns;
- qemu_log_try_set_file(stderr);
-
pc_start = tb->pc;
dc->env = env;
dc->tb = tb;
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 12ea820522..687b7d1433 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -1734,8 +1734,6 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb,
int num_insns;
int max_insns;
- qemu_log_try_set_file(stderr);
-
pc_start = tb->pc;
dc->env = env;
dc->tb = tb;
diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
index 96cb0447e2..841f47b91d 100644
--- a/target-mips/dsp_helper.c
+++ b/target-mips/dsp_helper.c
@@ -652,7 +652,7 @@ static inline int32_t mipsdsp_sat16_mul_q15_q15(uint16_t a, uint16_t b,
temp = 0x7FFF0000;
set_DSPControl_overflow_flag(1, 21, env);
} else {
- temp = ((uint32_t)a * (uint32_t)b);
+ temp = (int16_t)a * (int16_t)b;
temp = temp << 1;
}
@@ -2689,7 +2689,7 @@ MAQ_SA_W(maq_sa_w_phr, 0);
target_ulong helper_##name(target_ulong rs, target_ulong rt, \
CPUMIPSState *env) \
{ \
- uint32_t rs_t, rt_t; \
+ int32_t rs_t, rt_t; \
int32_t tempI; \
int64_t tempL; \
\
diff --git a/target-mips/helper.h b/target-mips/helper.h
index cd48738ff9..ed75e2c9f2 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -24,8 +24,6 @@ DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
#ifdef TARGET_MIPS64
DEF_HELPER_FLAGS_1(dclo, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(dclz, TCG_CALL_NO_RWG_SE, tl, tl)
-DEF_HELPER_3(dmult, void, env, tl, tl)
-DEF_HELPER_3(dmultu, void, env, tl, tl)
#endif
DEF_HELPER_3(muls, tl, env, tl, tl)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 526f84f136..45cbb2f1c2 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -267,18 +267,6 @@ target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
(uint64_t)(uint32_t)arg2);
}
-#ifdef TARGET_MIPS64
-void helper_dmult(CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
-{
- muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
-}
-
-void helper_dmultu(CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
-{
- mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
-}
-#endif
-
#ifndef CONFIG_USER_ONLY
static inline hwaddr do_translate_address(CPUMIPSState *env,
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 4ee9615fda..f10a533e80 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -2715,47 +2715,39 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
break;
case OPC_MULT:
{
- TCGv_i64 t2 = tcg_temp_new_i64();
- TCGv_i64 t3 = tcg_temp_new_i64();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv_i32 t3 = tcg_temp_new_i32();
acc = ((ctx->opcode) >> 11) & 0x03;
if (acc != 0) {
check_dsp(ctx);
}
- tcg_gen_ext_tl_i64(t2, t0);
- tcg_gen_ext_tl_i64(t3, t1);
- tcg_gen_mul_i64(t2, t2, t3);
- tcg_temp_free_i64(t3);
- tcg_gen_trunc_i64_tl(t0, t2);
- tcg_gen_shri_i64(t2, t2, 32);
- tcg_gen_trunc_i64_tl(t1, t2);
- tcg_temp_free_i64(t2);
- tcg_gen_ext32s_tl(cpu_LO[acc], t0);
- tcg_gen_ext32s_tl(cpu_HI[acc], t1);
+ tcg_gen_trunc_tl_i32(t2, t0);
+ tcg_gen_trunc_tl_i32(t3, t1);
+ tcg_gen_muls2_i32(t2, t3, t2, t3);
+ tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
+ tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
}
opn = "mult";
break;
case OPC_MULTU:
{
- TCGv_i64 t2 = tcg_temp_new_i64();
- TCGv_i64 t3 = tcg_temp_new_i64();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv_i32 t3 = tcg_temp_new_i32();
acc = ((ctx->opcode) >> 11) & 0x03;
if (acc != 0) {
check_dsp(ctx);
}
- tcg_gen_ext32u_tl(t0, t0);
- tcg_gen_ext32u_tl(t1, t1);
- tcg_gen_extu_tl_i64(t2, t0);
- tcg_gen_extu_tl_i64(t3, t1);
- tcg_gen_mul_i64(t2, t2, t3);
- tcg_temp_free_i64(t3);
- tcg_gen_trunc_i64_tl(t0, t2);
- tcg_gen_shri_i64(t2, t2, 32);
- tcg_gen_trunc_i64_tl(t1, t2);
- tcg_temp_free_i64(t2);
- tcg_gen_ext32s_tl(cpu_LO[acc], t0);
- tcg_gen_ext32s_tl(cpu_HI[acc], t1);
+ tcg_gen_trunc_tl_i32(t2, t0);
+ tcg_gen_trunc_tl_i32(t3, t1);
+ tcg_gen_mulu2_i32(t2, t3, t2, t3);
+ tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
+ tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
}
opn = "multu";
break;
@@ -2791,11 +2783,11 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
opn = "ddivu";
break;
case OPC_DMULT:
- gen_helper_dmult(cpu_env, t0, t1);
+ tcg_gen_muls2_i64(cpu_LO[0], cpu_HI[0], t0, t1);
opn = "dmult";
break;
case OPC_DMULTU:
- gen_helper_dmultu(cpu_env, t0, t1);
+ tcg_gen_mulu2_i64(cpu_LO[0], cpu_HI[0], t0, t1);
opn = "dmultu";
break;
#endif
diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
index 1e1b30cdcb..23e853e488 100644
--- a/target-openrisc/translate.c
+++ b/target-openrisc/translate.c
@@ -1670,8 +1670,6 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu,
int num_insns;
int max_insns;
- qemu_log_try_set_file(stderr);
-
pc_start = tb->pc;
dc->tb = tb;
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 8c081dbec5..20f4565a1a 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -941,8 +941,11 @@ struct CPUPPCState {
/* CFAR */
target_ulong cfar;
#endif
- /* XER */
+ /* XER (with SO, OV, CA split out) */
target_ulong xer;
+ target_ulong so;
+ target_ulong ov;
+ target_ulong ca;
/* Reservation address */
target_ulong reserve_addr;
/* Reservation value */
@@ -1268,9 +1271,9 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define XER_CA 29
#define XER_CMP 8
#define XER_BC 0
-#define xer_so ((env->xer >> XER_SO) & 1)
-#define xer_ov ((env->xer >> XER_OV) & 1)
-#define xer_ca ((env->xer >> XER_CA) & 1)
+#define xer_so (env->so)
+#define xer_ov (env->ov)
+#define xer_ca (env->ca)
#define xer_cmp ((env->xer >> XER_CMP) & 0xFF)
#define xer_bc ((env->xer >> XER_BC) & 0x7F)
@@ -2087,6 +2090,19 @@ enum {
/*****************************************************************************/
+static inline target_ulong cpu_read_xer(CPUPPCState *env)
+{
+ return env->xer | (env->so << XER_SO) | (env->ov << XER_OV) | (env->ca << XER_CA);
+}
+
+static inline void cpu_write_xer(CPUPPCState *env, target_ulong xer)
+{
+ env->so = (xer >> XER_SO) & 1;
+ env->ov = (xer >> XER_OV) & 1;
+ env->ca = (xer >> XER_CA) & 1;
+ env->xer = xer & ~((1u << XER_SO) | (1u << XER_OV) | (1u << XER_CA));
+}
+
static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 18e039452f..fcf372ab45 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -30,8 +30,6 @@ DEF_HELPER_2(icbi, void, env, tl)
DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32)
#if defined(TARGET_PPC64)
-DEF_HELPER_FLAGS_2(mulhd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(mulhdu, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_3(mulldo, i64, env, i64, i64)
#endif
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index 783079d995..54eca9bbee 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -25,24 +25,6 @@
/* Fixed point operations helpers */
#if defined(TARGET_PPC64)
-/* multiply high word */
-uint64_t helper_mulhd(uint64_t arg1, uint64_t arg2)
-{
- uint64_t tl, th;
-
- muls64(&tl, &th, arg1, arg2);
- return th;
-}
-
-/* multiply high word unsigned */
-uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2)
-{
- uint64_t tl, th;
-
- mulu64(&tl, &th, arg1, arg2);
- return th;
-}
-
uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
{
int64_t th;
@@ -51,9 +33,9 @@ uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
muls64(&tl, (uint64_t *)&th, arg1, arg2);
/* If th != 0 && th != -1, then we had an overflow */
if (likely((uint64_t)(th + 1) <= 1)) {
- env->xer &= ~(1 << XER_OV);
+ env->ov = 0;
} else {
- env->xer |= (1 << XER_OV) | (1 << XER_SO);
+ env->so = env->ov = 1;
}
return (int64_t)tl;
}
@@ -82,21 +64,17 @@ target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
shift &= 0x1f;
ret = (int32_t)value >> shift;
if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
- env->xer &= ~(1 << XER_CA);
+ env->ca = 0;
} else {
- env->xer |= (1 << XER_CA);
+ env->ca = 1;
}
} else {
ret = (int32_t)value;
- env->xer &= ~(1 << XER_CA);
+ env->ca = 0;
}
} else {
ret = (int32_t)value >> 31;
- if (ret) {
- env->xer |= (1 << XER_CA);
- } else {
- env->xer &= ~(1 << XER_CA);
- }
+ env->ca = (ret != 0);
}
return (target_long)ret;
}
@@ -112,21 +90,17 @@ target_ulong helper_srad(CPUPPCState *env, target_ulong value,
shift &= 0x3f;
ret = (int64_t)value >> shift;
if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
- env->xer &= ~(1 << XER_CA);
+ env->ca = 0;
} else {
- env->xer |= (1 << XER_CA);
+ env->ca = 1;
}
} else {
ret = (int64_t)value;
- env->xer &= ~(1 << XER_CA);
+ env->ca = 0;
}
} else {
ret = (int64_t)value >> 63;
- if (ret) {
- env->xer |= (1 << XER_CA);
- } else {
- env->xer &= ~(1 << XER_CA);
- }
+ env->ca = (ret != 0);
}
return ret;
}
@@ -206,16 +180,16 @@ target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
- env->xer |= (1 << XER_OV) | (1 << XER_SO);
+ env->so = env->ov = 1;
env->spr[SPR_MQ] = 0;
return INT32_MIN;
} else {
env->spr[SPR_MQ] = tmp % arg2;
tmp /= (int32_t)arg2;
if ((int32_t)tmp != tmp) {
- env->xer |= (1 << XER_OV) | (1 << XER_SO);
+ env->so = env->ov = 1;
} else {
- env->xer &= ~(1 << XER_OV);
+ env->ov = 0;
}
return tmp;
}
@@ -239,11 +213,11 @@ target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
{
if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
- env->xer |= (1 << XER_OV) | (1 << XER_SO);
+ env->so = env->ov = 1;
env->spr[SPR_MQ] = 0;
return INT32_MIN;
} else {
- env->xer &= ~(1 << XER_OV);
+ env->ov = 0;
env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
return (int32_t)arg1 / (int32_t)arg2;
}
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 2c64c634f1..8e6441614e 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -464,7 +464,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
regs.ctr = env->ctr;
regs.lr = env->lr;
- regs.xer = env->xer;
+ regs.xer = cpu_read_xer(env);
regs.msr = env->msr;
regs.pc = env->nip;
@@ -566,7 +566,7 @@ int kvm_arch_get_registers(CPUState *cs)
env->ctr = regs.ctr;
env->lr = regs.lr;
- env->xer = regs.xer;
+ cpu_write_xer(env, regs.xer);
env->msr = regs.msr;
env->nip = regs.pc;
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index e014c0c1af..708a840da7 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -7,6 +7,7 @@ void cpu_save(QEMUFile *f, void *opaque)
CPUPPCState *env = (CPUPPCState *)opaque;
unsigned int i, j;
uint32_t fpscr;
+ target_ulong xer;
for (i = 0; i < 32; i++)
qemu_put_betls(f, &env->gpr[i]);
@@ -18,7 +19,8 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_betls(f, &env->ctr);
for (i = 0; i < 8; i++)
qemu_put_be32s(f, &env->crf[i]);
- qemu_put_betls(f, &env->xer);
+ xer = cpu_read_xer(env);
+ qemu_put_betls(f, &xer);
qemu_put_betls(f, &env->reserve_addr);
qemu_put_betls(f, &env->msr);
for (i = 0; i < 4; i++)
@@ -93,6 +95,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
unsigned int i, j;
target_ulong sdr1;
uint32_t fpscr;
+ target_ulong xer;
for (i = 0; i < 32; i++)
qemu_get_betls(f, &env->gpr[i]);
@@ -104,7 +107,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_betls(f, &env->ctr);
for (i = 0; i < 8; i++)
qemu_get_be32s(f, &env->crf[i]);
- qemu_get_betls(f, &env->xer);
+ qemu_get_betls(f, &xer);
+ cpu_write_xer(env, xer);
qemu_get_betls(f, &env->reserve_addr);
qemu_get_betls(f, &env->msr);
for (i = 0; i < 4; i++)
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 2ac5794add..80d5366d27 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -66,7 +66,7 @@ static TCGv cpu_lr;
#if defined(TARGET_PPC64)
static TCGv cpu_cfar;
#endif
-static TCGv cpu_xer;
+static TCGv cpu_xer, cpu_so, cpu_ov, cpu_ca;
static TCGv cpu_reserve;
static TCGv cpu_fpscr;
static TCGv_i32 cpu_access_type;
@@ -158,6 +158,12 @@ void ppc_translate_init(void)
cpu_xer = tcg_global_mem_new(TCG_AREG0,
offsetof(CPUPPCState, xer), "xer");
+ cpu_so = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUPPCState, so), "SO");
+ cpu_ov = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUPPCState, ov), "OV");
+ cpu_ca = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUPPCState, ca), "CA");
cpu_reserve = tcg_global_mem_new(TCG_AREG0,
offsetof(CPUPPCState, reserve_addr),
@@ -590,35 +596,33 @@ static opc_handler_t invalid_handler = {
static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
{
- int l1, l2, l3;
+ TCGv t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new_i32();
- tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_xer);
- tcg_gen_shri_i32(cpu_crf[crf], cpu_crf[crf], XER_SO);
- tcg_gen_andi_i32(cpu_crf[crf], cpu_crf[crf], 1);
+ tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_so);
- l1 = gen_new_label();
- l2 = gen_new_label();
- l3 = gen_new_label();
- if (s) {
- tcg_gen_brcond_tl(TCG_COND_LT, arg0, arg1, l1);
- tcg_gen_brcond_tl(TCG_COND_GT, arg0, arg1, l2);
- } else {
- tcg_gen_brcond_tl(TCG_COND_LTU, arg0, arg1, l1);
- tcg_gen_brcond_tl(TCG_COND_GTU, arg0, arg1, l2);
- }
- tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_EQ);
- tcg_gen_br(l3);
- gen_set_label(l1);
- tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_LT);
- tcg_gen_br(l3);
- gen_set_label(l2);
- tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_GT);
- gen_set_label(l3);
+ tcg_gen_setcond_tl((s ? TCG_COND_LT: TCG_COND_LTU), t0, arg0, arg1);
+ tcg_gen_trunc_tl_i32(t1, t0);
+ tcg_gen_shli_i32(t1, t1, CRF_LT);
+ tcg_gen_or_i32(cpu_crf[crf], cpu_crf[crf], t1);
+
+ tcg_gen_setcond_tl((s ? TCG_COND_GT: TCG_COND_GTU), t0, arg0, arg1);
+ tcg_gen_trunc_tl_i32(t1, t0);
+ tcg_gen_shli_i32(t1, t1, CRF_GT);
+ tcg_gen_or_i32(cpu_crf[crf], cpu_crf[crf], t1);
+
+ tcg_gen_setcond_tl(TCG_COND_EQ, t0, arg0, arg1);
+ tcg_gen_trunc_tl_i32(t1, t0);
+ tcg_gen_shli_i32(t1, t1, CRF_EQ);
+ tcg_gen_or_i32(cpu_crf[crf], cpu_crf[crf], t1);
+
+ tcg_temp_free(t0);
+ tcg_temp_free_i32(t1);
}
static inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf)
{
- TCGv t0 = tcg_const_local_tl(arg1);
+ TCGv t0 = tcg_const_tl(arg1);
gen_op_cmp(arg0, t0, s, crf);
tcg_temp_free(t0);
}
@@ -627,8 +631,8 @@ static inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf)
static inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf)
{
TCGv t0, t1;
- t0 = tcg_temp_local_new();
- t1 = tcg_temp_local_new();
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
if (s) {
tcg_gen_ext32s_tl(t0, arg0);
tcg_gen_ext32s_tl(t1, arg1);
@@ -643,7 +647,7 @@ static inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf)
static inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf)
{
- TCGv t0 = tcg_const_local_tl(arg1);
+ TCGv t0 = tcg_const_tl(arg1);
gen_op_cmp32(arg0, t0, s, crf);
tcg_temp_free(t0);
}
@@ -742,120 +746,59 @@ static void gen_isel(DisasContext *ctx)
static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
TCGv arg1, TCGv arg2, int sub)
{
- int l1;
- TCGv t0;
+ TCGv t0 = tcg_temp_new();
- l1 = gen_new_label();
- /* Start with XER OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
- t0 = tcg_temp_local_new();
- tcg_gen_xor_tl(t0, arg0, arg1);
-#if defined(TARGET_PPC64)
- if (!ctx->sf_mode)
- tcg_gen_ext32s_tl(t0, t0);
-#endif
- if (sub)
- tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1);
- else
- tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1);
+ tcg_gen_xor_tl(cpu_ov, arg0, arg1);
tcg_gen_xor_tl(t0, arg1, arg2);
-#if defined(TARGET_PPC64)
- if (!ctx->sf_mode)
- tcg_gen_ext32s_tl(t0, t0);
-#endif
- if (sub)
- tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1);
- else
- tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1);
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
- gen_set_label(l1);
+ if (sub) {
+ tcg_gen_and_tl(cpu_ov, cpu_ov, t0);
+ } else {
+ tcg_gen_andc_tl(cpu_ov, cpu_ov, t0);
+ }
tcg_temp_free(t0);
-}
-
-static inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1,
- TCGv arg2, int sub)
-{
- int l1 = gen_new_label();
-
#if defined(TARGET_PPC64)
- if (!(ctx->sf_mode)) {
- TCGv t0, t1;
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
-
- tcg_gen_ext32u_tl(t0, arg1);
- tcg_gen_ext32u_tl(t1, arg2);
- if (sub) {
- tcg_gen_brcond_tl(TCG_COND_GTU, t0, t1, l1);
- } else {
- tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
- }
- tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
- gen_set_label(l1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- } else
-#endif
- {
- if (sub) {
- tcg_gen_brcond_tl(TCG_COND_GTU, arg1, arg2, l1);
- } else {
- tcg_gen_brcond_tl(TCG_COND_GEU, arg1, arg2, l1);
- }
- tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
- gen_set_label(l1);
+ if (!ctx->sf_mode) {
+ tcg_gen_ext32s_tl(cpu_ov, cpu_ov);
}
+#endif
+ tcg_gen_shri_tl(cpu_ov, cpu_ov, TARGET_LONG_BITS - 1);
+ tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
/* Common add function */
static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
- TCGv arg2, int add_ca, int compute_ca,
- int compute_ov)
+ TCGv arg2, bool add_ca, bool compute_ca,
+ bool compute_ov, bool compute_rc0)
{
- TCGv t0, t1;
+ TCGv t0 = ret;
- if ((!compute_ca && !compute_ov) ||
- (!TCGV_EQUAL(ret,arg1) && !TCGV_EQUAL(ret, arg2))) {
- t0 = ret;
- } else {
- t0 = tcg_temp_local_new();
+ if (((compute_ca && add_ca) || compute_ov)
+ && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) {
+ t0 = tcg_temp_new();
}
- if (add_ca) {
- t1 = tcg_temp_local_new();
- tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
- tcg_gen_shri_tl(t1, t1, XER_CA);
+ if (compute_ca) {
+ TCGv zero = tcg_const_tl(0);
+ if (add_ca) {
+ tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero);
+ tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero);
+ } else {
+ tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero);
+ }
+ tcg_temp_free(zero);
} else {
- TCGV_UNUSED(t1);
- }
-
- if (compute_ca && compute_ov) {
- /* Start with XER CA and OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV)));
- } else if (compute_ca) {
- /* Start with XER CA disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
- } else if (compute_ov) {
- /* Start with XER OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+ tcg_gen_add_tl(t0, arg1, arg2);
+ if (add_ca) {
+ tcg_gen_add_tl(t0, t0, cpu_ca);
+ }
}
- tcg_gen_add_tl(t0, arg1, arg2);
-
- if (compute_ca) {
- gen_op_arith_compute_ca(ctx, t0, arg1, 0);
- }
- if (add_ca) {
- tcg_gen_add_tl(t0, t0, t1);
- gen_op_arith_compute_ca(ctx, t0, t1, 0);
- tcg_temp_free(t1);
- }
if (compute_ov) {
gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 0);
}
-
- if (unlikely(Rc(ctx->opcode) != 0))
+ if (unlikely(compute_rc0)) {
gen_set_Rc0(ctx, t0);
+ }
if (!TCGV_EQUAL(t0, ret)) {
tcg_gen_mov_tl(ret, t0);
@@ -864,21 +807,21 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
}
/* Add functions with two operands */
#define GEN_INT_ARITH_ADD(name, opc3, add_ca, compute_ca, compute_ov) \
-static void glue(gen_, name)(DisasContext *ctx) \
+static void glue(gen_, name)(DisasContext *ctx) \
{ \
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
- add_ca, compute_ca, compute_ov); \
+ add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
}
/* Add functions with one operand and one immediate */
#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val, \
add_ca, compute_ca, compute_ov) \
-static void glue(gen_, name)(DisasContext *ctx) \
+static void glue(gen_, name)(DisasContext *ctx) \
{ \
- TCGv t0 = tcg_const_local_tl(const_val); \
+ TCGv t0 = tcg_const_tl(const_val); \
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \
cpu_gpr[rA(ctx->opcode)], t0, \
- add_ca, compute_ca, compute_ov); \
+ add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
tcg_temp_free(t0); \
}
@@ -906,40 +849,27 @@ static void gen_addi(DisasContext *ctx)
/* li case */
tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm);
} else {
- tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm);
+ tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)],
+ cpu_gpr[rA(ctx->opcode)], simm);
}
}
/* addic addic.*/
-static inline void gen_op_addic(DisasContext *ctx, TCGv ret, TCGv arg1,
- int compute_Rc0)
+static inline void gen_op_addic(DisasContext *ctx, bool compute_rc0)
{
- target_long simm = SIMM(ctx->opcode);
-
- /* Start with XER CA and OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
-
- if (likely(simm != 0)) {
- TCGv t0 = tcg_temp_local_new();
- tcg_gen_addi_tl(t0, arg1, simm);
- gen_op_arith_compute_ca(ctx, t0, arg1, 0);
- tcg_gen_mov_tl(ret, t0);
- tcg_temp_free(t0);
- } else {
- tcg_gen_mov_tl(ret, arg1);
- }
- if (compute_Rc0) {
- gen_set_Rc0(ctx, ret);
- }
+ TCGv c = tcg_const_tl(SIMM(ctx->opcode));
+ gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+ c, 0, 1, 0, compute_rc0);
+ tcg_temp_free(c);
}
static void gen_addic(DisasContext *ctx)
{
- gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
+ gen_op_addic(ctx, 0);
}
static void gen_addic_(DisasContext *ctx)
{
- gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
+ gen_op_addic(ctx, 1);
}
/* addis */
@@ -951,7 +881,8 @@ static void gen_addis(DisasContext *ctx)
/* lis case */
tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm << 16);
} else {
- tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm << 16);
+ tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)],
+ cpu_gpr[rA(ctx->opcode)], simm << 16);
}
}
@@ -976,7 +907,7 @@ static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_gen_divu_i32(t0, t0, t1);
}
if (compute_ov) {
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+ tcg_gen_movi_tl(cpu_ov, 0);
}
tcg_gen_br(l2);
gen_set_label(l1);
@@ -986,7 +917,8 @@ static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_gen_movi_i32(t0, 0);
}
if (compute_ov) {
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+ tcg_gen_movi_tl(cpu_ov, 1);
+ tcg_gen_movi_tl(cpu_so, 1);
}
gen_set_label(l2);
tcg_gen_extu_i32_tl(ret, t0);
@@ -1027,7 +959,7 @@ static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_gen_divu_i64(ret, arg1, arg2);
}
if (compute_ov) {
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+ tcg_gen_movi_tl(cpu_ov, 0);
}
tcg_gen_br(l2);
gen_set_label(l1);
@@ -1037,7 +969,8 @@ static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_gen_movi_i64(ret, 0);
}
if (compute_ov) {
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+ tcg_gen_movi_tl(cpu_ov, 1);
+ tcg_gen_movi_tl(cpu_so, 1);
}
gen_set_label(l2);
if (unlikely(Rc(ctx->opcode) != 0))
@@ -1061,24 +994,15 @@ GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1);
/* mulhw mulhw. */
static void gen_mulhw(DisasContext *ctx)
{
- TCGv_i64 t0, t1;
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t1 = tcg_temp_new_i32();
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
-#if defined(TARGET_PPC64)
- tcg_gen_ext32s_tl(t0, cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_ext32s_tl(t1, cpu_gpr[rB(ctx->opcode)]);
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32);
-#else
- tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0);
-#endif
- tcg_temp_free_i64(t0);
- tcg_temp_free_i64(t1);
+ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);
+ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);
+ tcg_gen_muls2_i32(t0, t1, t0, t1);
+ tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
@@ -1086,24 +1010,15 @@ static void gen_mulhw(DisasContext *ctx)
/* mulhwu mulhwu. */
static void gen_mulhwu(DisasContext *ctx)
{
- TCGv_i64 t0, t1;
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t1 = tcg_temp_new_i32();
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
-#if defined(TARGET_PPC64)
- tcg_gen_ext32u_i64(t0, cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_ext32u_i64(t1, cpu_gpr[rB(ctx->opcode)]);
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32);
-#else
- tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0);
-#endif
- tcg_temp_free_i64(t0);
- tcg_temp_free_i64(t1);
+ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);
+ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);
+ tcg_gen_mulu2_i32(t0, t1, t0, t1);
+ tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
@@ -1121,34 +1036,21 @@ static void gen_mullw(DisasContext *ctx)
/* mullwo mullwo. */
static void gen_mullwo(DisasContext *ctx)
{
- int l1;
- TCGv_i64 t0, t1;
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t1 = tcg_temp_new_i32();
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
- l1 = gen_new_label();
- /* Start with XER OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
-#if defined(TARGET_PPC64)
- tcg_gen_ext32s_i64(t0, cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_ext32s_i64(t1, cpu_gpr[rB(ctx->opcode)]);
-#else
- tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
-#endif
- tcg_gen_mul_i64(t0, t0, t1);
-#if defined(TARGET_PPC64)
- tcg_gen_ext32s_i64(cpu_gpr[rD(ctx->opcode)], t0);
- tcg_gen_brcond_i64(TCG_COND_EQ, t0, cpu_gpr[rD(ctx->opcode)], l1);
-#else
- tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0);
- tcg_gen_ext32s_i64(t1, t0);
- tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
-#endif
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
- gen_set_label(l1);
- tcg_temp_free_i64(t0);
- tcg_temp_free_i64(t1);
+ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);
+ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);
+ tcg_gen_muls2_i32(t0, t1, t0, t1);
+ tcg_gen_ext_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);
+
+ tcg_gen_sari_i32(t0, t0, 31);
+ tcg_gen_setcond_i32(TCG_COND_NE, t0, t0, t1);
+ tcg_gen_extu_i32_tl(cpu_ov, t0);
+ tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
@@ -1159,19 +1061,31 @@ static void gen_mulli(DisasContext *ctx)
tcg_gen_muli_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
SIMM(ctx->opcode));
}
+
#if defined(TARGET_PPC64)
-#define GEN_INT_ARITH_MUL_HELPER(name, opc3) \
-static void glue(gen_, name)(DisasContext *ctx) \
-{ \
- gen_helper_##name (cpu_gpr[rD(ctx->opcode)], \
- cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \
- if (unlikely(Rc(ctx->opcode) != 0)) \
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); \
-}
/* mulhd mulhd. */
-GEN_INT_ARITH_MUL_HELPER(mulhdu, 0x00);
+static void gen_mulhd(DisasContext *ctx)
+{
+ TCGv lo = tcg_temp_new();
+ tcg_gen_muls2_tl(lo, cpu_gpr[rD(ctx->opcode)],
+ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+ tcg_temp_free(lo);
+ if (unlikely(Rc(ctx->opcode) != 0)) {
+ gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+ }
+}
+
/* mulhdu mulhdu. */
-GEN_INT_ARITH_MUL_HELPER(mulhd, 0x02);
+static void gen_mulhdu(DisasContext *ctx)
+{
+ TCGv lo = tcg_temp_new();
+ tcg_gen_mulu2_tl(lo, cpu_gpr[rD(ctx->opcode)],
+ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+ tcg_temp_free(lo);
+ if (unlikely(Rc(ctx->opcode) != 0)) {
+ gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+ }
+}
/* mulld mulld. */
static void gen_mulld(DisasContext *ctx)
@@ -1193,101 +1107,46 @@ static void gen_mulldo(DisasContext *ctx)
}
#endif
-/* neg neg. nego nego. */
-static inline void gen_op_arith_neg(DisasContext *ctx, TCGv ret, TCGv arg1,
- int ov_check)
-{
- int l1 = gen_new_label();
- int l2 = gen_new_label();
- TCGv t0 = tcg_temp_local_new();
-#if defined(TARGET_PPC64)
- if (ctx->sf_mode) {
- tcg_gen_mov_tl(t0, arg1);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT64_MIN, l1);
- } else
-#endif
- {
- tcg_gen_ext32s_tl(t0, arg1);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT32_MIN, l1);
- }
- tcg_gen_neg_tl(ret, arg1);
- if (ov_check) {
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
- }
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_mov_tl(ret, t0);
- if (ov_check) {
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
- }
- gen_set_label(l2);
- tcg_temp_free(t0);
- if (unlikely(Rc(ctx->opcode) != 0))
- gen_set_Rc0(ctx, ret);
-}
-
-static void gen_neg(DisasContext *ctx)
-{
- gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
-}
-
-static void gen_nego(DisasContext *ctx)
-{
- gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
-}
-
/* Common subf function */
static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
- TCGv arg2, int add_ca, int compute_ca,
- int compute_ov)
+ TCGv arg2, bool add_ca, bool compute_ca,
+ bool compute_ov, bool compute_rc0)
{
- TCGv t0, t1;
-
- if ((!compute_ca && !compute_ov) ||
- (!TCGV_EQUAL(ret, arg1) && !TCGV_EQUAL(ret, arg2))) {
- t0 = ret;
- } else {
- t0 = tcg_temp_local_new();
- }
+ TCGv t0 = ret;
- if (add_ca) {
- t1 = tcg_temp_local_new();
- tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
- tcg_gen_shri_tl(t1, t1, XER_CA);
- } else {
- TCGV_UNUSED(t1);
- }
-
- if (compute_ca && compute_ov) {
- /* Start with XER CA and OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV)));
- } else if (compute_ca) {
- /* Start with XER CA disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
- } else if (compute_ov) {
- /* Start with XER OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+ if (((add_ca && compute_ca) || compute_ov)
+ && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) {
+ t0 = tcg_temp_new();
}
if (add_ca) {
- tcg_gen_not_tl(t0, arg1);
- tcg_gen_add_tl(t0, t0, arg2);
- gen_op_arith_compute_ca(ctx, t0, arg2, 0);
- tcg_gen_add_tl(t0, t0, t1);
- gen_op_arith_compute_ca(ctx, t0, t1, 0);
- tcg_temp_free(t1);
+ /* dest = ~arg1 + arg2 + ca. */
+ if (compute_ca) {
+ TCGv zero, inv1 = tcg_temp_new();
+ tcg_gen_not_tl(inv1, arg1);
+ zero = tcg_const_tl(0);
+ tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero);
+ tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, inv1, zero);
+ tcg_temp_free(zero);
+ tcg_temp_free(inv1);
+ } else {
+ tcg_gen_sub_tl(t0, arg2, arg1);
+ tcg_gen_add_tl(t0, t0, cpu_ca);
+ tcg_gen_subi_tl(t0, t0, 1);
+ }
} else {
- tcg_gen_sub_tl(t0, arg2, arg1);
if (compute_ca) {
- gen_op_arith_compute_ca(ctx, t0, arg2, 1);
+ tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1);
}
+ tcg_gen_sub_tl(t0, arg2, arg1);
}
+
if (compute_ov) {
gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 1);
}
-
- if (unlikely(Rc(ctx->opcode) != 0))
+ if (unlikely(compute_rc0)) {
gen_set_Rc0(ctx, t0);
+ }
if (!TCGV_EQUAL(t0, ret)) {
tcg_gen_mov_tl(ret, t0);
@@ -1296,21 +1155,21 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
}
/* Sub functions with Two operands functions */
#define GEN_INT_ARITH_SUBF(name, opc3, add_ca, compute_ca, compute_ov) \
-static void glue(gen_, name)(DisasContext *ctx) \
+static void glue(gen_, name)(DisasContext *ctx) \
{ \
gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], \
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
- add_ca, compute_ca, compute_ov); \
+ add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
}
/* Sub functions with one operand and one immediate */
#define GEN_INT_ARITH_SUBF_CONST(name, opc3, const_val, \
add_ca, compute_ca, compute_ov) \
-static void glue(gen_, name)(DisasContext *ctx) \
+static void glue(gen_, name)(DisasContext *ctx) \
{ \
- TCGv t0 = tcg_const_local_tl(const_val); \
+ TCGv t0 = tcg_const_tl(const_val); \
gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], \
cpu_gpr[rA(ctx->opcode)], t0, \
- add_ca, compute_ca, compute_ov); \
+ add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
tcg_temp_free(t0); \
}
/* subf subf. subfo subfo. */
@@ -1332,15 +1191,29 @@ GEN_INT_ARITH_SUBF_CONST(subfzeo, 0x16, 0, 1, 1, 1)
/* subfic */
static void gen_subfic(DisasContext *ctx)
{
- /* Start with XER CA and OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
- TCGv t0 = tcg_temp_local_new();
- TCGv t1 = tcg_const_local_tl(SIMM(ctx->opcode));
- tcg_gen_sub_tl(t0, t1, cpu_gpr[rA(ctx->opcode)]);
- gen_op_arith_compute_ca(ctx, t0, t1, 1);
- tcg_temp_free(t1);
- tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
- tcg_temp_free(t0);
+ TCGv c = tcg_const_tl(SIMM(ctx->opcode));
+ gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+ c, 0, 1, 0, 0);
+ tcg_temp_free(c);
+}
+
+/* neg neg. nego nego. */
+static inline void gen_op_arith_neg(DisasContext *ctx, bool compute_ov)
+{
+ TCGv zero = tcg_const_tl(0);
+ gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+ zero, 0, 0, compute_ov, Rc(ctx->opcode));
+ tcg_temp_free(zero);
+}
+
+static void gen_neg(DisasContext *ctx)
+{
+ gen_op_arith_neg(ctx, 0);
+}
+
+static void gen_nego(DisasContext *ctx)
+{
+ gen_op_arith_neg(ctx, 1);
}
/*** Integer logical ***/
@@ -1887,30 +1760,25 @@ static void gen_sraw(DisasContext *ctx)
static void gen_srawi(DisasContext *ctx)
{
int sh = SH(ctx->opcode);
- if (sh != 0) {
- int l1, l2;
+ TCGv dst = cpu_gpr[rA(ctx->opcode)];
+ TCGv src = cpu_gpr[rS(ctx->opcode)];
+ if (sh == 0) {
+ tcg_gen_mov_tl(dst, src);
+ tcg_gen_movi_tl(cpu_ca, 0);
+ } else {
TCGv t0;
- l1 = gen_new_label();
- l2 = gen_new_label();
- t0 = tcg_temp_local_new();
- tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]);
- tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1);
- tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
- tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
- gen_set_label(l2);
- tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]);
- tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], t0, sh);
+ tcg_gen_ext32s_tl(dst, src);
+ tcg_gen_andi_tl(cpu_ca, dst, (1ULL << sh) - 1);
+ t0 = tcg_temp_new();
+ tcg_gen_sari_tl(t0, dst, TARGET_LONG_BITS - 1);
+ tcg_gen_and_tl(cpu_ca, cpu_ca, t0);
tcg_temp_free(t0);
- } else {
- tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+ tcg_gen_setcondi_tl(TCG_COND_NE, cpu_ca, cpu_ca, 0);
+ tcg_gen_sari_tl(dst, dst, sh);
+ }
+ if (unlikely(Rc(ctx->opcode) != 0)) {
+ gen_set_Rc0(ctx, dst);
}
- if (unlikely(Rc(ctx->opcode) != 0))
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
/* srw & srw. */
@@ -1970,28 +1838,24 @@ static void gen_srad(DisasContext *ctx)
static inline void gen_sradi(DisasContext *ctx, int n)
{
int sh = SH(ctx->opcode) + (n << 5);
- if (sh != 0) {
- int l1, l2;
+ TCGv dst = cpu_gpr[rA(ctx->opcode)];
+ TCGv src = cpu_gpr[rS(ctx->opcode)];
+ if (sh == 0) {
+ tcg_gen_mov_tl(dst, src);
+ tcg_gen_movi_tl(cpu_ca, 0);
+ } else {
TCGv t0;
- l1 = gen_new_label();
- l2 = gen_new_label();
- t0 = tcg_temp_local_new();
- tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1);
- tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
- tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
- gen_set_label(l2);
+ tcg_gen_andi_tl(cpu_ca, src, (1ULL << sh) - 1);
+ t0 = tcg_temp_new();
+ tcg_gen_sari_tl(t0, src, TARGET_LONG_BITS - 1);
+ tcg_gen_and_tl(cpu_ca, cpu_ca, t0);
tcg_temp_free(t0);
- tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
- } else {
- tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+ tcg_gen_setcondi_tl(TCG_COND_NE, cpu_ca, cpu_ca, 0);
+ tcg_gen_sari_tl(dst, src, sh);
+ }
+ if (unlikely(Rc(ctx->opcode) != 0)) {
+ gen_set_Rc0(ctx, dst);
}
- if (unlikely(Rc(ctx->opcode) != 0))
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
static void gen_sradi0(DisasContext *ctx)
@@ -3176,9 +3040,7 @@ static void gen_stwcx_(DisasContext *ctx)
{
int l1;
- tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
- tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
- tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
+ tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
l1 = gen_new_label();
tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
@@ -3219,9 +3081,7 @@ static void gen_stdcx_(DisasContext *ctx)
#else
{
int l1;
- tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
- tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
- tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
+ tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
l1 = gen_new_label();
tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
@@ -3797,12 +3657,55 @@ static void gen_tdi(DisasContext *ctx)
/*** Processor control ***/
+static void gen_read_xer(TCGv dst)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+ tcg_gen_mov_tl(dst, cpu_xer);
+ tcg_gen_shli_tl(t0, cpu_so, XER_SO);
+ tcg_gen_shli_tl(t1, cpu_ov, XER_OV);
+ tcg_gen_shli_tl(t2, cpu_ca, XER_CA);
+ tcg_gen_or_tl(t0, t0, t1);
+ tcg_gen_or_tl(dst, dst, t2);
+ tcg_gen_or_tl(dst, dst, t0);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+}
+
+static void gen_write_xer(TCGv src)
+{
+ tcg_gen_andi_tl(cpu_xer, src,
+ ~((1u << XER_SO) | (1u << XER_OV) | (1u << XER_CA)));
+ tcg_gen_shri_tl(cpu_so, src, XER_SO);
+ tcg_gen_shri_tl(cpu_ov, src, XER_OV);
+ tcg_gen_shri_tl(cpu_ca, src, XER_CA);
+ tcg_gen_andi_tl(cpu_so, cpu_so, 1);
+ tcg_gen_andi_tl(cpu_ov, cpu_ov, 1);
+ tcg_gen_andi_tl(cpu_ca, cpu_ca, 1);
+}
+
/* mcrxr */
static void gen_mcrxr(DisasContext *ctx)
{
- tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], cpu_xer);
- tcg_gen_shri_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], XER_CA);
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_SO | 1 << XER_OV | 1 << XER_CA));
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 dst = cpu_crf[crfD(ctx->opcode)];
+
+ tcg_gen_trunc_tl_i32(t0, cpu_so);
+ tcg_gen_trunc_tl_i32(t1, cpu_ov);
+ tcg_gen_trunc_tl_i32(dst, cpu_ca);
+ tcg_gen_shri_i32(t0, t0, 2);
+ tcg_gen_shri_i32(t1, t1, 1);
+ tcg_gen_or_i32(dst, dst, t0);
+ tcg_gen_or_i32(dst, dst, t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+
+ tcg_gen_movi_tl(cpu_so, 0);
+ tcg_gen_movi_tl(cpu_ov, 0);
+ tcg_gen_movi_tl(cpu_ca, 0);
}
/* mfcr mfocrf */
@@ -4532,10 +4435,11 @@ static void gen_abso(DisasContext *ctx)
int l2 = gen_new_label();
int l3 = gen_new_label();
/* Start with XER OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+ tcg_gen_movi_tl(cpu_ov, 0);
tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l2);
tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rA(ctx->opcode)], 0x80000000, l1);
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+ tcg_gen_movi_tl(cpu_ov, 1);
+ tcg_gen_movi_tl(cpu_so, 1);
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
@@ -4616,7 +4520,7 @@ static void gen_dozo(DisasContext *ctx)
TCGv t1 = tcg_temp_new();
TCGv t2 = tcg_temp_new();
/* Start with XER OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+ tcg_gen_movi_tl(cpu_ov, 0);
tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1);
tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
@@ -4624,7 +4528,8 @@ static void gen_dozo(DisasContext *ctx)
tcg_gen_andc_tl(t1, t1, t2);
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+ tcg_gen_movi_tl(cpu_ov, 1);
+ tcg_gen_movi_tl(cpu_so, 1);
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
@@ -4742,7 +4647,7 @@ static void gen_mulo(DisasContext *ctx)
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv t2 = tcg_temp_new();
/* Start with XER OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+ tcg_gen_movi_tl(cpu_ov, 0);
tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
tcg_gen_mul_i64(t0, t0, t1);
@@ -4752,7 +4657,8 @@ static void gen_mulo(DisasContext *ctx)
tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
tcg_gen_ext32s_i64(t1, t0);
tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+ tcg_gen_movi_tl(cpu_ov, 1);
+ tcg_gen_movi_tl(cpu_so, 1);
gen_set_label(l1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(t1);
@@ -4788,7 +4694,7 @@ static void gen_nabso(DisasContext *ctx)
tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
gen_set_label(l2);
/* nabs never overflows */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+ tcg_gen_movi_tl(cpu_ov, 0);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
@@ -4965,10 +4871,10 @@ static void gen_sraiq(DisasContext *ctx)
tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
tcg_gen_or_tl(t0, t0, t1);
gen_store_spr(SPR_MQ, t0);
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+ tcg_gen_movi_tl(cpu_ca, 0);
tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1);
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA));
+ tcg_gen_movi_tl(cpu_ca, 1);
gen_set_label(l1);
tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
tcg_temp_free(t0);
@@ -4999,10 +4905,10 @@ static void gen_sraq(DisasContext *ctx)
gen_set_label(l1);
tcg_temp_free(t0);
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t1);
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+ tcg_gen_movi_tl(cpu_ca, 0);
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l2);
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA));
+ tcg_gen_movi_tl(cpu_ca, 1);
gen_set_label(l2);
tcg_temp_free(t1);
tcg_temp_free(t2);
@@ -5571,7 +5477,7 @@ static inline void gen_405_mulladd_insn(DisasContext *ctx, int opc2, int opc3,
if (opc3 & 0x10) {
/* Start with XER OV disabled, the most likely case */
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+ tcg_gen_movi_tl(cpu_ov, 0);
}
if (opc3 & 0x01) {
/* Signed */
@@ -5594,7 +5500,8 @@ static inline void gen_405_mulladd_insn(DisasContext *ctx, int opc2, int opc3,
}
if (opc3 & 0x10) {
/* Check overflow */
- tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+ tcg_gen_movi_tl(cpu_ov, 1);
+ tcg_gen_movi_tl(cpu_so, 1);
}
gen_set_label(l1);
tcg_gen_mov_tl(cpu_gpr[rt], t0);
@@ -5982,9 +5889,7 @@ static void gen_tlbsx_40x(DisasContext *ctx)
tcg_temp_free(t0);
if (Rc(ctx->opcode)) {
int l1 = gen_new_label();
- tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
- tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
- tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
+ tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
gen_set_label(l1);
@@ -6065,9 +5970,7 @@ static void gen_tlbsx_440(DisasContext *ctx)
tcg_temp_free(t0);
if (Rc(ctx->opcode)) {
int l1 = gen_new_label();
- tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
- tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
- tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
+ tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
gen_set_label(l1);
@@ -9416,7 +9319,7 @@ void cpu_dump_state (CPUPPCState *env, FILE *f, fprintf_function cpu_fprintf,
cpu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR "
TARGET_FMT_lx " XER " TARGET_FMT_lx "\n",
- env->nip, env->lr, env->ctr, env->xer);
+ env->nip, env->lr, env->ctr, cpu_read_xer(env));
cpu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF "
TARGET_FMT_lx " idx %d\n", env->msr, env->spr[SPR_HID0],
env->hflags, env->mmu_idx);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 5df205757b..f5fc9b18f0 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -118,12 +118,12 @@ static void spr_write_clear (void *opaque, int sprn, int gprn)
/* XER */
static void spr_read_xer (void *opaque, int gprn, int sprn)
{
- tcg_gen_mov_tl(cpu_gpr[gprn], cpu_xer);
+ gen_read_xer(cpu_gpr[gprn]);
}
static void spr_write_xer (void *opaque, int sprn, int gprn)
{
- tcg_gen_mov_tl(cpu_xer, cpu_gpr[gprn]);
+ gen_write_xer(cpu_gpr[gprn]);
}
/* LR */
diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index dd90d93bee..0d80aa046f 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -8,7 +8,6 @@ DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_3(mvcl, i32, env, i32, i32)
DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64)
-DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64)
DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64)
diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c
index 685830124f..af16b21baa 100644
--- a/target-s390x/int_helper.c
+++ b/target-s390x/int_helper.c
@@ -29,14 +29,6 @@
#define HELPER_LOG(x...)
#endif
-/* 64/64 -> 128 unsigned multiplication */
-uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2)
-{
- uint64_t reth;
- mulu64(&env->retxl, &reth, v1, v2);
- return reth;
-}
-
/* 64/32 -> 32 signed division */
int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
{
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index a57296c64f..bdf69a3c7c 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -2566,8 +2566,7 @@ static ExitStatus op_mul(DisasContext *s, DisasOps *o)
static ExitStatus op_mul128(DisasContext *s, DisasOps *o)
{
- gen_helper_mul128(o->out, cpu_env, o->in1, o->in2);
- return_low128(o->out2);
+ tcg_gen_mulu2_i64(o->out2, o->out, o->in1, o->in2);
return NO_EXIT;
}
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index c58d79a5cd..d255066e0a 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -833,36 +833,10 @@ static void _decode_opc(DisasContext * ctx)
gen_helper_div1(REG(B11_8), cpu_env, REG(B7_4), REG(B11_8));
return;
case 0x300d: /* dmuls.l Rm,Rn */
- {
- TCGv_i64 tmp1 = tcg_temp_new_i64();
- TCGv_i64 tmp2 = tcg_temp_new_i64();
-
- tcg_gen_ext_i32_i64(tmp1, REG(B7_4));
- tcg_gen_ext_i32_i64(tmp2, REG(B11_8));
- tcg_gen_mul_i64(tmp1, tmp1, tmp2);
- tcg_gen_trunc_i64_i32(cpu_macl, tmp1);
- tcg_gen_shri_i64(tmp1, tmp1, 32);
- tcg_gen_trunc_i64_i32(cpu_mach, tmp1);
-
- tcg_temp_free_i64(tmp2);
- tcg_temp_free_i64(tmp1);
- }
+ tcg_gen_muls2_i32(cpu_macl, cpu_mach, REG(B7_4), REG(B11_8));
return;
case 0x3005: /* dmulu.l Rm,Rn */
- {
- TCGv_i64 tmp1 = tcg_temp_new_i64();
- TCGv_i64 tmp2 = tcg_temp_new_i64();
-
- tcg_gen_extu_i32_i64(tmp1, REG(B7_4));
- tcg_gen_extu_i32_i64(tmp2, REG(B11_8));
- tcg_gen_mul_i64(tmp1, tmp1, tmp2);
- tcg_gen_trunc_i64_i32(cpu_macl, tmp1);
- tcg_gen_shri_i64(tmp1, tmp1, 32);
- tcg_gen_trunc_i64_i32(cpu_mach, tmp1);
-
- tcg_temp_free_i64(tmp2);
- tcg_temp_free_i64(tmp1);
- }
+ tcg_gen_mulu2_i32(cpu_macl, cpu_mach, REG(B7_4), REG(B11_8));
return;
case 0x600e: /* exts.b Rm,Rn */
tcg_gen_ext8s_i32(REG(B11_8), REG(B7_4));
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index ef52df6d74..50def61848 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -580,13 +580,13 @@ static const sparc_def_t sparc_defs[] = {
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
.mmu_version = 0xf3000000,
.mmu_bm = 0x00000000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
+ .mmu_ctpr_mask = 0xfffffffc,
+ .mmu_cxr_mask = 0x000000ff,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
- CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
+ CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL | CPU_FEATURE_POWERDOWN,
},
#endif
};
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 7389b03514..a2f2cc8989 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -270,6 +270,7 @@ typedef struct sparc_def_t {
#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
#define CPU_FEATURE_ASR17 (1 << 15)
#define CPU_FEATURE_CACHE_CTRL (1 << 16)
+#define CPU_FEATURE_POWERDOWN (1 << 17)
#ifndef TARGET_SPARC64
#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 91ecfc7aa8..58e7efe567 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -225,3 +225,14 @@ target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
cpu_restore_state(env, GETPC());
helper_raise_exception(env, TT_TOVF);
}
+
+#ifndef TARGET_SPARC64
+void helper_power_down(CPUSPARCState *env)
+{
+ env->halted = 1;
+ env->exception_index = EXCP_HLT;
+ env->pc = env->npc;
+ env->npc = env->pc + 4;
+ cpu_loop_exit(env);
+}
+#endif
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index cfcdab1ea4..15f73283fa 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -4,6 +4,7 @@
DEF_HELPER_1(rett, void, env)
DEF_HELPER_2(wrpsr, void, env, tl)
DEF_HELPER_1(rdpsr, tl, env)
+DEF_HELPER_1(power_down, void, env)
#else
DEF_HELPER_2(wrpil, void, env, tl)
DEF_HELPER_2(wrpstate, void, env, tl)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 7decd66d0b..6d767fb45a 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -514,6 +514,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
#endif
break;
case 3: /* MMU probe */
+ case 0x18: /* LEON3 MMU probe */
{
int mmulev;
@@ -528,6 +529,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
}
break;
case 4: /* read MMU regs */
+ case 0x19: /* LEON3 read MMU regs */
{
int reg = (addr >> 8) & 0x1f;
@@ -603,6 +605,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
case 0xf: /* D-cache data */
break;
case 0x20: /* MMU passthrough */
+ case 0x1c: /* LEON MMU passthrough */
switch (size) {
case 1:
ret = ldub_phys(addr);
@@ -844,6 +847,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
#endif
break;
case 3: /* MMU flush */
+ case 0x18: /* LEON3 MMU flush */
{
int mmulev;
@@ -868,6 +872,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
}
break;
case 4: /* write MMU regs */
+ case 0x19: /* LEON3 write MMU regs */
{
int reg = (addr >> 8) & 0x1f;
uint32_t oldreg;
@@ -996,6 +1001,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
}
break;
case 0x20: /* MMU passthrough */
+ case 0x1c: /* LEON MMU passthrough */
{
switch (size) {
case 1:
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index ca75e1aa48..12276d5608 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -448,19 +448,16 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
case CC_OP_ADD:
case CC_OP_TADD:
case CC_OP_TADDTV:
-#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32
- {
- /* For 32-bit hosts, we can re-use the host's hardware carry
- generation by using an ADD2 opcode. We discard the low
- part of the output. Ideally we'd combine this operation
- with the add that generated the carry in the first place. */
- TCGv dst_low = tcg_temp_new();
- tcg_gen_op6_i32(INDEX_op_add2_i32, dst_low, dst,
- cpu_cc_src, src1, cpu_cc_src2, src2);
- tcg_temp_free(dst_low);
+ if (TARGET_LONG_BITS == 32) {
+ /* We can re-use the host's hardware carry generation by using
+ an ADD2 opcode. We discard the low part of the output.
+ Ideally we'd combine this operation with the add that
+ generated the carry in the first place. */
+ carry = tcg_temp_new();
+ tcg_gen_add2_tl(carry, dst, cpu_cc_src, src1, cpu_cc_src2, src2);
+ tcg_temp_free(carry);
goto add_done;
}
-#endif
carry_32 = gen_add32_carry32();
break;
@@ -492,9 +489,7 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
tcg_temp_free(carry);
#endif
-#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32
add_done:
-#endif
if (update_cc) {
tcg_gen_mov_tl(cpu_cc_src, src1);
tcg_gen_mov_tl(cpu_cc_src2, src2);
@@ -554,19 +549,16 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
case CC_OP_SUB:
case CC_OP_TSUB:
case CC_OP_TSUBTV:
-#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32
- {
- /* For 32-bit hosts, we can re-use the host's hardware carry
- generation by using a SUB2 opcode. We discard the low
- part of the output. Ideally we'd combine this operation
- with the add that generated the carry in the first place. */
- TCGv dst_low = tcg_temp_new();
- tcg_gen_op6_i32(INDEX_op_sub2_i32, dst_low, dst,
- cpu_cc_src, src1, cpu_cc_src2, src2);
- tcg_temp_free(dst_low);
+ if (TARGET_LONG_BITS == 32) {
+ /* We can re-use the host's hardware carry generation by using
+ a SUB2 opcode. We discard the low part of the output.
+ Ideally we'd combine this operation with the add that
+ generated the carry in the first place. */
+ carry = tcg_temp_new();
+ tcg_gen_sub2_tl(carry, dst, cpu_cc_src, src1, cpu_cc_src2, src2);
+ tcg_temp_free(carry);
goto sub_done;
}
-#endif
carry_32 = gen_sub32_carry32();
break;
@@ -592,9 +584,7 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
tcg_temp_free(carry);
#endif
-#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32
sub_done:
-#endif
if (update_cc) {
tcg_gen_mov_tl(cpu_cc_src, src1);
tcg_gen_mov_tl(cpu_cc_src2, src2);
@@ -652,39 +642,30 @@ static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
static inline void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext)
{
- TCGv_i32 r_src1, r_src2;
- TCGv_i64 r_temp, r_temp2;
-
- r_src1 = tcg_temp_new_i32();
- r_src2 = tcg_temp_new_i32();
-
- tcg_gen_trunc_tl_i32(r_src1, src1);
- tcg_gen_trunc_tl_i32(r_src2, src2);
-
- r_temp = tcg_temp_new_i64();
- r_temp2 = tcg_temp_new_i64();
-
+#if TARGET_LONG_BITS == 32
if (sign_ext) {
- tcg_gen_ext_i32_i64(r_temp, r_src2);
- tcg_gen_ext_i32_i64(r_temp2, r_src1);
+ tcg_gen_muls2_tl(dst, cpu_y, src1, src2);
} else {
- tcg_gen_extu_i32_i64(r_temp, r_src2);
- tcg_gen_extu_i32_i64(r_temp2, r_src1);
+ tcg_gen_mulu2_tl(dst, cpu_y, src1, src2);
}
+#else
+ TCGv t0 = tcg_temp_new_i64();
+ TCGv t1 = tcg_temp_new_i64();
- tcg_gen_mul_i64(r_temp2, r_temp, r_temp2);
-
- tcg_gen_shri_i64(r_temp, r_temp2, 32);
- tcg_gen_trunc_i64_tl(cpu_y, r_temp);
- tcg_temp_free_i64(r_temp);
- tcg_gen_andi_tl(cpu_y, cpu_y, 0xffffffff);
-
- tcg_gen_trunc_i64_tl(dst, r_temp2);
+ if (sign_ext) {
+ tcg_gen_ext32s_i64(t0, src1);
+ tcg_gen_ext32s_i64(t1, src2);
+ } else {
+ tcg_gen_ext32u_i64(t0, src1);
+ tcg_gen_ext32u_i64(t1, src2);
+ }
- tcg_temp_free_i64(r_temp2);
+ tcg_gen_mul_i64(dst, t0, t1);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
- tcg_temp_free_i32(r_src1);
- tcg_temp_free_i32(r_src2);
+ tcg_gen_shri_i64(cpu_y, dst, 32);
+#endif
}
static inline void gen_op_umul(TCGv dst, TCGv src1, TCGv src2)
@@ -3642,6 +3623,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
in the SPARCv8
manual, nop on the
microSPARC II */
+ if ((rd == 0x13) && (dc->def->features &
+ CPU_FEATURE_POWERDOWN)) {
+ /* LEON3 power-down */
+ gen_helper_power_down(cpu_env);
+ }
break;
#else
case 0x2: /* V9 wrccr */
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index f4498bcb14..d5039e2093 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -267,37 +267,6 @@ static void gen_exception(int excp)
dead_tmp(tmp);
}
-/* FIXME: Most targets have native widening multiplication.
- It would be good to use that instead of a full wide multiply. */
-/* 32x32->64 multiply. Marks inputs as dead. */
-static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
-{
- TCGv_i64 tmp1 = tcg_temp_new_i64();
- TCGv_i64 tmp2 = tcg_temp_new_i64();
-
- tcg_gen_extu_i32_i64(tmp1, a);
- dead_tmp(a);
- tcg_gen_extu_i32_i64(tmp2, b);
- dead_tmp(b);
- tcg_gen_mul_i64(tmp1, tmp1, tmp2);
- tcg_temp_free_i64(tmp2);
- return tmp1;
-}
-
-static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
-{
- TCGv_i64 tmp1 = tcg_temp_new_i64();
- TCGv_i64 tmp2 = tcg_temp_new_i64();
-
- tcg_gen_ext_i32_i64(tmp1, a);
- dead_tmp(a);
- tcg_gen_ext_i32_i64(tmp2, b);
- dead_tmp(b);
- tcg_gen_mul_i64(tmp1, tmp1, tmp2);
- tcg_temp_free_i64(tmp2);
- return tmp1;
-}
-
#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, CF))
/* Set CF to the top bit of var. */
@@ -1219,38 +1188,6 @@ static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s,
}
}
-
-/* Store a 64-bit value to a register pair. Clobbers val. */
-static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
-{
- TCGv tmp;
- tmp = new_tmp();
- tcg_gen_trunc_i64_i32(tmp, val);
- store_reg(s, rlow, tmp);
- tmp = new_tmp();
- tcg_gen_shri_i64(val, val, 32);
- tcg_gen_trunc_i64_i32(tmp, val);
- store_reg(s, rhigh, tmp);
-}
-
-/* load and add a 64-bit value from a register pair. */
-static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
-{
- TCGv_i64 tmp;
- TCGv tmpl;
- TCGv tmph;
-
- /* Load 64-bit value rd:rn. */
- tmpl = load_reg(s, rlow);
- tmph = load_reg(s, rhigh);
- tmp = tcg_temp_new_i64();
- tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
- dead_tmp(tmpl);
- dead_tmp(tmph);
- tcg_gen_add_i64(val, val, tmp);
- tcg_temp_free_i64(tmp);
-}
-
/* data processing instructions */
static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
{
@@ -1445,24 +1382,26 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
/* multiply */
static void do_mult(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
{
- TCGv tmp;
- TCGv tmp2;
- TCGv_i64 tmp64;
+ TCGv tmp, tmp2, tmp3, tmp4;
if (UCOP_SET(27)) {
/* 64 bit mul */
tmp = load_reg(s, UCOP_REG_M);
tmp2 = load_reg(s, UCOP_REG_N);
if (UCOP_SET(26)) {
- tmp64 = gen_muls_i64_i32(tmp, tmp2);
+ tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);
} else {
- tmp64 = gen_mulu_i64_i32(tmp, tmp2);
+ tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);
}
if (UCOP_SET(25)) { /* mult accumulate */
- gen_addq(s, tmp64, UCOP_REG_LO, UCOP_REG_HI);
- }
- gen_storeq_reg(s, UCOP_REG_LO, UCOP_REG_HI, tmp64);
- tcg_temp_free_i64(tmp64);
+ tmp3 = load_reg(s, UCOP_REG_LO);
+ tmp4 = load_reg(s, UCOP_REG_HI);
+ tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, tmp3, tmp4);
+ dead_tmp(tmp3);
+ dead_tmp(tmp4);
+ }
+ store_reg(s, UCOP_REG_LO, tmp);
+ store_reg(s, UCOP_REG_HI, tmp2);
} else {
/* 32 bit mul */
tmp = load_reg(s, UCOP_REG_M);
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 7029ac4814..11e06a34f5 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -1652,24 +1652,16 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
case 11: /*MULSHi*/
HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL_HIGH);
{
- TCGv_i64 r = tcg_temp_new_i64();
- TCGv_i64 s = tcg_temp_new_i64();
- TCGv_i64 t = tcg_temp_new_i64();
+ TCGv lo = tcg_temp_new();
if (OP2 == 10) {
- tcg_gen_extu_i32_i64(s, cpu_R[RRR_S]);
- tcg_gen_extu_i32_i64(t, cpu_R[RRR_T]);
+ tcg_gen_mulu2_i32(lo, cpu_R[RRR_R],
+ cpu_R[RRR_S], cpu_R[RRR_T]);
} else {
- tcg_gen_ext_i32_i64(s, cpu_R[RRR_S]);
- tcg_gen_ext_i32_i64(t, cpu_R[RRR_T]);
+ tcg_gen_muls2_i32(lo, cpu_R[RRR_R],
+ cpu_R[RRR_S], cpu_R[RRR_T]);
}
- tcg_gen_mul_i64(r, s, t);
- tcg_gen_shri_i64(r, r, 32);
- tcg_gen_trunc_i64_i32(cpu_R[RRR_R], r);
-
- tcg_temp_free_i64(r);
- tcg_temp_free_i64(s);
- tcg_temp_free_i64(t);
+ tcg_temp_free(lo);
}
break;
@@ -2495,27 +2487,24 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
tcg_gen_sari_i32(cpu_SR[ACCHI], cpu_SR[ACCLO], 31);
}
} else {
- TCGv_i32 res = tcg_temp_new_i32();
- TCGv_i64 res64 = tcg_temp_new_i64();
- TCGv_i64 tmp = tcg_temp_new_i64();
-
- tcg_gen_mul_i32(res, m1, m2);
- tcg_gen_ext_i32_i64(res64, res);
- tcg_gen_concat_i32_i64(tmp,
- cpu_SR[ACCLO], cpu_SR[ACCHI]);
+ TCGv_i32 lo = tcg_temp_new_i32();
+ TCGv_i32 hi = tcg_temp_new_i32();
+
+ tcg_gen_mul_i32(lo, m1, m2);
+ tcg_gen_sari_i32(hi, lo, 31);
if (op == MAC16_MULA) {
- tcg_gen_add_i64(tmp, tmp, res64);
+ tcg_gen_add2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI],
+ cpu_SR[ACCLO], cpu_SR[ACCHI],
+ lo, hi);
} else {
- tcg_gen_sub_i64(tmp, tmp, res64);
+ tcg_gen_sub2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI],
+ cpu_SR[ACCLO], cpu_SR[ACCHI],
+ lo, hi);
}
- tcg_gen_trunc_i64_i32(cpu_SR[ACCLO], tmp);
- tcg_gen_shri_i64(tmp, tmp, 32);
- tcg_gen_trunc_i64_i32(cpu_SR[ACCHI], tmp);
tcg_gen_ext8s_i32(cpu_SR[ACCHI], cpu_SR[ACCHI]);
- tcg_temp_free(res);
- tcg_temp_free_i64(res64);
- tcg_temp_free_i64(tmp);
+ tcg_temp_free_i32(lo);
+ tcg_temp_free_i32(hi);
}
tcg_temp_free(m1);
tcg_temp_free(m2);
diff --git a/tcg-runtime.c b/tcg-runtime.c
index abfc36498f..4b66e51ce7 100644
--- a/tcg-runtime.c
+++ b/tcg-runtime.c
@@ -22,7 +22,7 @@
* THE SOFTWARE.
*/
#include <stdint.h>
-
+#include "qemu/host-utils.h"
#include "tcg/tcg-runtime.h"
/* 32-bit helpers */
@@ -83,3 +83,17 @@ uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2)
{
return arg1 % arg2;
}
+
+uint64_t tcg_helper_muluh_i64(uint64_t arg1, uint64_t arg2)
+{
+ uint64_t l, h;
+ mulu64(&l, &h, arg1, arg2);
+ return h;
+}
+
+int64_t tcg_helper_mulsh_i64(int64_t arg1, int64_t arg2)
+{
+ uint64_t l, h;
+ muls64(&l, &h, arg1, arg2);
+ return h;
+}
diff --git a/tcg/README b/tcg/README
index ec1ac79375..934e7afc96 100644
--- a/tcg/README
+++ b/tcg/README
@@ -361,6 +361,24 @@ Write 8, 16, 32 or 64 bits to host memory.
All this opcodes assume that the pointed host memory doesn't correspond
to a global. In the latter case the behaviour is unpredictable.
+********* Multiword arithmetic support
+
+* add2_i32/i64 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
+* sub2_i32/i64 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
+
+Similar to add/sub, except that the double-word inputs T1 and T2 are
+formed from two single-word arguments, and the double-word output T0
+is returned in two single-word outputs.
+
+* mulu2_i32/i64 t0_low, t0_high, t1, t2
+
+Similar to mul, except two unsigned inputs T1 and T2 yielding the full
+double-word product T0. The later is returned in two single-word outputs.
+
+* muls2_i32/i64 t0_low, t0_high, t1, t2
+
+Similar to mulu2, except the two inputs T1 and T2 are signed.
+
********* 64-bit target on 32-bit host support
The following opcodes are internal to TCG. Thus they are to be implemented by
@@ -372,18 +390,6 @@ They are emitted as needed by inline functions within "tcg-op.h".
Similar to brcond, except that the 64-bit values T0 and T1
are formed from two 32-bit arguments.
-* add2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
-* sub2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
-
-Similar to add/sub, except that the 64-bit inputs T1 and T2 are
-formed from two 32-bit arguments, and the 64-bit output T0
-is returned in two 32-bit outputs.
-
-* mulu2_i32 t0_low, t0_high, t1, t2
-
-Similar to mul, except two 32-bit (unsigned) inputs T1 and T2 yielding
-the full 64-bit product T0. The later is returned in two 32-bit outputs.
-
* setcond2_i32 dest, t1_low, t1_high, t2_low, t2_high, cond
Similar to setcond, except that the 64-bit values T1 and T2 are
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index d9c33d850f..94c6ca43aa 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -1647,6 +1647,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
case INDEX_op_mulu2_i32:
tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]);
break;
+ case INDEX_op_muls2_i32:
+ tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]);
+ break;
/* XXX: Perhaps args[2] & 0x1f is wrong */
case INDEX_op_shl_i32:
c = const_args[2] ?
@@ -1798,6 +1801,7 @@ static const TCGTargetOpDef arm_op_defs[] = {
{ INDEX_op_sub_i32, { "r", "r", "rI" } },
{ INDEX_op_mul_i32, { "r", "r", "r" } },
{ INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
+ { INDEX_op_muls2_i32, { "r", "r", "r", "r" } },
{ INDEX_op_and_i32, { "r", "r", "rI" } },
{ INDEX_op_andc_i32, { "r", "r", "rI" } },
{ INDEX_op_or_i32, { "r", "r", "rI" } },
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 7083f3a700..b6eed1f3f4 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -75,6 +75,7 @@ typedef enum {
#define TCG_TARGET_HAS_nor_i32 0
#define TCG_TARGET_HAS_deposit_i32 0
#define TCG_TARGET_HAS_movcond_i32 1
+#define TCG_TARGET_HAS_muls2_i32 1
enum {
TCG_AREG0 = TCG_REG_R6,
diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h
index e2754fe970..ebd53d9e36 100644
--- a/tcg/hppa/tcg-target.h
+++ b/tcg/hppa/tcg-target.h
@@ -98,6 +98,7 @@ typedef enum {
#define TCG_TARGET_HAS_nor_i32 0
#define TCG_TARGET_HAS_deposit_i32 1
#define TCG_TARGET_HAS_movcond_i32 1
+#define TCG_TARGET_HAS_muls2_i32 0
/* optional instructions automatically implemented */
#define TCG_TARGET_HAS_neg_i32 0 /* sub rd, 0, rs */
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 7aec3043e3..9eec06c8a4 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -1922,40 +1922,44 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_qemu_st(s, args, 3);
break;
-#if TCG_TARGET_REG_BITS == 32
- case INDEX_op_brcond2_i32:
- tcg_out_brcond2(s, args, const_args, 0);
+ OP_32_64(mulu2):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_MUL, args[3]);
break;
- case INDEX_op_setcond2_i32:
- tcg_out_setcond2(s, args, const_args);
+ OP_32_64(muls2):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IMUL, args[3]);
break;
- case INDEX_op_mulu2_i32:
- tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_MUL, args[3]);
- break;
- case INDEX_op_add2_i32:
+ OP_32_64(add2):
if (const_args[4]) {
- tgen_arithi(s, ARITH_ADD, args[0], args[4], 1);
+ tgen_arithi(s, ARITH_ADD + rexw, args[0], args[4], 1);
} else {
- tgen_arithr(s, ARITH_ADD, args[0], args[4]);
+ tgen_arithr(s, ARITH_ADD + rexw, args[0], args[4]);
}
if (const_args[5]) {
- tgen_arithi(s, ARITH_ADC, args[1], args[5], 1);
+ tgen_arithi(s, ARITH_ADC + rexw, args[1], args[5], 1);
} else {
- tgen_arithr(s, ARITH_ADC, args[1], args[5]);
+ tgen_arithr(s, ARITH_ADC + rexw, args[1], args[5]);
}
break;
- case INDEX_op_sub2_i32:
+ OP_32_64(sub2):
if (const_args[4]) {
- tgen_arithi(s, ARITH_SUB, args[0], args[4], 1);
+ tgen_arithi(s, ARITH_SUB + rexw, args[0], args[4], 1);
} else {
- tgen_arithr(s, ARITH_SUB, args[0], args[4]);
+ tgen_arithr(s, ARITH_SUB + rexw, args[0], args[4]);
}
if (const_args[5]) {
- tgen_arithi(s, ARITH_SBB, args[1], args[5], 1);
+ tgen_arithi(s, ARITH_SBB + rexw, args[1], args[5], 1);
} else {
- tgen_arithr(s, ARITH_SBB, args[1], args[5]);
+ tgen_arithr(s, ARITH_SBB + rexw, args[1], args[5]);
}
break;
+
+#if TCG_TARGET_REG_BITS == 32
+ case INDEX_op_brcond2_i32:
+ tcg_out_brcond2(s, args, const_args, 0);
+ break;
+ case INDEX_op_setcond2_i32:
+ tcg_out_setcond2(s, args, const_args);
+ break;
#else /* TCG_TARGET_REG_BITS == 64 */
case INDEX_op_movi_i64:
tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
@@ -2078,10 +2082,12 @@ static const TCGTargetOpDef x86_op_defs[] = {
{ INDEX_op_movcond_i32, { "r", "r", "ri", "r", "0" } },
#endif
-#if TCG_TARGET_REG_BITS == 32
{ INDEX_op_mulu2_i32, { "a", "d", "a", "r" } },
+ { INDEX_op_muls2_i32, { "a", "d", "a", "r" } },
{ INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } },
{ INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } },
+
+#if TCG_TARGET_REG_BITS == 32
{ INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } },
{ INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
#else
@@ -2132,6 +2138,11 @@ static const TCGTargetOpDef x86_op_defs[] = {
{ INDEX_op_deposit_i64, { "Q", "0", "Q" } },
{ INDEX_op_movcond_i64, { "r", "r", "re", "r", "0" } },
+
+ { INDEX_op_mulu2_i64, { "a", "d", "a", "r" } },
+ { INDEX_op_muls2_i64, { "a", "d", "a", "r" } },
+ { INDEX_op_add2_i64, { "r", "r", "0", "1", "re", "re" } },
+ { INDEX_op_sub2_i64, { "r", "r", "0", "1", "re", "re" } },
#endif
#if TCG_TARGET_REG_BITS == 64
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index e63db9cfe9..e3f6bb965f 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -92,6 +92,10 @@ typedef enum {
#define TCG_TARGET_HAS_nor_i32 0
#define TCG_TARGET_HAS_deposit_i32 1
#define TCG_TARGET_HAS_movcond_i32 1
+#define TCG_TARGET_HAS_add2_i32 1
+#define TCG_TARGET_HAS_sub2_i32 1
+#define TCG_TARGET_HAS_mulu2_i32 1
+#define TCG_TARGET_HAS_muls2_i32 1
#if TCG_TARGET_REG_BITS == 64
#define TCG_TARGET_HAS_div2_i64 1
@@ -114,6 +118,10 @@ typedef enum {
#define TCG_TARGET_HAS_nor_i64 0
#define TCG_TARGET_HAS_deposit_i64 1
#define TCG_TARGET_HAS_movcond_i64 1
+#define TCG_TARGET_HAS_add2_i64 1
+#define TCG_TARGET_HAS_sub2_i64 1
+#define TCG_TARGET_HAS_mulu2_i64 1
+#define TCG_TARGET_HAS_muls2_i64 1
#endif
#define TCG_TARGET_deposit_i32_valid(ofs, len) \
diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h
index 7f3401ecdd..e3d72ea52f 100644
--- a/tcg/ia64/tcg-target.h
+++ b/tcg/ia64/tcg-target.h
@@ -136,6 +136,14 @@ typedef enum {
#define TCG_TARGET_HAS_movcond_i64 1
#define TCG_TARGET_HAS_deposit_i32 1
#define TCG_TARGET_HAS_deposit_i64 1
+#define TCG_TARGET_HAS_add2_i32 0
+#define TCG_TARGET_HAS_add2_i64 0
+#define TCG_TARGET_HAS_sub2_i32 0
+#define TCG_TARGET_HAS_sub2_i64 0
+#define TCG_TARGET_HAS_mulu2_i32 0
+#define TCG_TARGET_HAS_mulu2_i64 0
+#define TCG_TARGET_HAS_muls2_i32 0
+#define TCG_TARGET_HAS_muls2_i64 0
#define TCG_TARGET_deposit_i32_valid(ofs, len) ((len) <= 16)
#define TCG_TARGET_deposit_i64_valid(ofs, len) ((len) <= 16)
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index 78af664cca..0384bd384f 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -87,6 +87,7 @@ typedef enum {
#define TCG_TARGET_HAS_orc_i32 0
#define TCG_TARGET_HAS_eqv_i32 0
#define TCG_TARGET_HAS_nand_i32 0
+#define TCG_TARGET_HAS_muls2_i32 0
/* optional instructions only implemented on MIPS4, MIPS32 and Loongson 2 */
#if (defined(__mips_isa_rev) && (__mips_isa_rev >= 1)) || \
diff --git a/tcg/optimize.c b/tcg/optimize.c
index 973d2d679f..bc6e5c16a9 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -554,11 +554,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
args[5] = tcg_invert_cond(args[5]);
}
break;
- case INDEX_op_add2_i32:
+ CASE_OP_32_64(add2):
swap_commutative(args[0], &args[2], &args[4]);
swap_commutative(args[1], &args[3], &args[5]);
break;
- case INDEX_op_mulu2_i32:
+ CASE_OP_32_64(mulu2):
+ CASE_OP_32_64(muls2):
swap_commutative(args[0], &args[2], &args[3]);
break;
case INDEX_op_brcond2_i32:
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 0fdad04ee4..17a6bb367a 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -94,6 +94,7 @@ typedef enum {
#define TCG_TARGET_HAS_nor_i32 1
#define TCG_TARGET_HAS_deposit_i32 1
#define TCG_TARGET_HAS_movcond_i32 1
+#define TCG_TARGET_HAS_muls2_i32 0
#define TCG_AREG0 TCG_REG_R27
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
index 9b8e9a07b8..aa6a0f0306 100644
--- a/tcg/ppc64/tcg-target.h
+++ b/tcg/ppc64/tcg-target.h
@@ -85,6 +85,10 @@ typedef enum {
#define TCG_TARGET_HAS_nor_i32 0
#define TCG_TARGET_HAS_deposit_i32 0
#define TCG_TARGET_HAS_movcond_i32 0
+#define TCG_TARGET_HAS_add2_i32 0
+#define TCG_TARGET_HAS_sub2_i32 0
+#define TCG_TARGET_HAS_mulu2_i32 0
+#define TCG_TARGET_HAS_muls2_i32 0
#define TCG_TARGET_HAS_div_i64 1
#define TCG_TARGET_HAS_rot_i64 0
@@ -106,6 +110,10 @@ typedef enum {
#define TCG_TARGET_HAS_nor_i64 0
#define TCG_TARGET_HAS_deposit_i64 0
#define TCG_TARGET_HAS_movcond_i64 0
+#define TCG_TARGET_HAS_add2_i64 0
+#define TCG_TARGET_HAS_sub2_i64 0
+#define TCG_TARGET_HAS_mulu2_i64 0
+#define TCG_TARGET_HAS_muls2_i64 0
#define TCG_AREG0 TCG_REG_R27
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index c87b4138b5..40211e68f1 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -65,6 +65,10 @@ typedef enum TCGReg {
#define TCG_TARGET_HAS_nor_i32 0
#define TCG_TARGET_HAS_deposit_i32 0
#define TCG_TARGET_HAS_movcond_i32 0
+#define TCG_TARGET_HAS_add2_i32 0
+#define TCG_TARGET_HAS_sub2_i32 0
+#define TCG_TARGET_HAS_mulu2_i32 0
+#define TCG_TARGET_HAS_muls2_i32 0
#if TCG_TARGET_REG_BITS == 64
#define TCG_TARGET_HAS_div2_i64 1
@@ -87,6 +91,10 @@ typedef enum TCGReg {
#define TCG_TARGET_HAS_nor_i64 0
#define TCG_TARGET_HAS_deposit_i64 0
#define TCG_TARGET_HAS_movcond_i64 0
+#define TCG_TARGET_HAS_add2_i64 0
+#define TCG_TARGET_HAS_sub2_i64 0
+#define TCG_TARGET_HAS_mulu2_i64 0
+#define TCG_TARGET_HAS_muls2_i64 0
#endif
/* used for function call generation */
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 03db514a1d..6d489fcc52 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -1327,6 +1327,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
args[3], const_args[3],
args[4], const_args[4]);
break;
+#endif
+
case INDEX_op_add2_i32:
tcg_out_addsub2(s, args[0], args[1], args[2], args[3],
args[4], const_args[4], args[5], const_args[5],
@@ -1342,7 +1344,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
ARITH_UMUL);
tcg_out_rdy(s, args[1]);
break;
-#endif
case INDEX_op_qemu_ld8u:
tcg_out_qemu_ld(s, args, 0);
@@ -1511,10 +1512,11 @@ static const TCGTargetOpDef sparc_op_defs[] = {
#if TCG_TARGET_REG_BITS == 32
{ INDEX_op_brcond2_i32, { "rZ", "rZ", "rJ", "rJ" } },
{ INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rJ", "rJ" } },
+#endif
+
{ INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } },
{ INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } },
{ INDEX_op_mulu2_i32, { "r", "r", "rZ", "rJ" } },
-#endif
#if TCG_TARGET_REG_BITS == 64
{ INDEX_op_mov_i64, { "r", "r" } },
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 256f973c6d..b5217bef25 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -102,6 +102,10 @@ typedef enum {
#define TCG_TARGET_HAS_nor_i32 0
#define TCG_TARGET_HAS_deposit_i32 0
#define TCG_TARGET_HAS_movcond_i32 1
+#define TCG_TARGET_HAS_add2_i32 1
+#define TCG_TARGET_HAS_sub2_i32 1
+#define TCG_TARGET_HAS_mulu2_i32 1
+#define TCG_TARGET_HAS_muls2_i32 0
#if TCG_TARGET_REG_BITS == 64
#define TCG_TARGET_HAS_div_i64 1
@@ -124,6 +128,10 @@ typedef enum {
#define TCG_TARGET_HAS_nor_i64 0
#define TCG_TARGET_HAS_deposit_i64 0
#define TCG_TARGET_HAS_movcond_i64 1
+#define TCG_TARGET_HAS_add2_i64 0
+#define TCG_TARGET_HAS_sub2_i64 0
+#define TCG_TARGET_HAS_mulu2_i64 0
+#define TCG_TARGET_HAS_muls2_i64 0
#endif
#define TCG_AREG0 TCG_REG_I0
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 91c9d80dd5..d70b2eba33 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -2246,6 +2246,26 @@ static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low,
tcg_gen_deposit_i64(dest, low, high, 32, 32);
}
+static inline void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg)
+{
+#if TCG_TARGET_REG_BITS == 32
+ tcg_gen_mov_i32(lo, TCGV_LOW(arg));
+ tcg_gen_mov_i32(hi, TCGV_HIGH(arg));
+#else
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_trunc_i64_i32(lo, arg);
+ tcg_gen_shri_i64(t0, arg, 32);
+ tcg_gen_trunc_i64_i32(hi, t0);
+ tcg_temp_free_i64(t0);
+#endif
+}
+
+static inline void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg)
+{
+ tcg_gen_ext32u_i64(lo, arg);
+ tcg_gen_shri_i64(hi, arg, 32);
+}
+
static inline void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret,
TCGv_i32 c1, TCGv_i32 c2,
TCGv_i32 v1, TCGv_i32 v2)
@@ -2312,6 +2332,204 @@ static inline void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret,
#endif
}
+static inline void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al,
+ TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh)
+{
+ if (TCG_TARGET_HAS_add2_i32) {
+ tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh);
+ /* Allow the optimizer room to replace add2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ tcg_gen_concat_i32_i64(t0, al, ah);
+ tcg_gen_concat_i32_i64(t1, bl, bh);
+ tcg_gen_add_i64(t0, t0, t1);
+ tcg_gen_extr_i64_i32(rl, rh, t0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ }
+}
+
+static inline void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al,
+ TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh)
+{
+ if (TCG_TARGET_HAS_sub2_i32) {
+ tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh);
+ /* Allow the optimizer room to replace sub2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ tcg_gen_concat_i32_i64(t0, al, ah);
+ tcg_gen_concat_i32_i64(t1, bl, bh);
+ tcg_gen_sub_i64(t0, t0, t1);
+ tcg_gen_extr_i64_i32(rl, rh, t0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ }
+}
+
+static inline void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh,
+ TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ if (TCG_TARGET_HAS_mulu2_i32) {
+ tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2);
+ /* Allow the optimizer room to replace mulu2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(t0, arg1);
+ tcg_gen_extu_i32_i64(t1, arg2);
+ tcg_gen_mul_i64(t0, t0, t1);
+ tcg_gen_extr_i64_i32(rl, rh, t0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ }
+}
+
+static inline void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh,
+ TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ if (TCG_TARGET_HAS_muls2_i32) {
+ tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2);
+ /* Allow the optimizer room to replace muls2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ } else if (TCG_TARGET_REG_BITS == 32 && TCG_TARGET_HAS_mulu2_i32) {
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv_i32 t3 = tcg_temp_new_i32();
+ tcg_gen_op4_i32(INDEX_op_mulu2_i32, t0, t1, arg1, arg2);
+ /* Allow the optimizer room to replace mulu2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ /* Adjust for negative inputs. */
+ tcg_gen_sari_i32(t2, arg1, 31);
+ tcg_gen_sari_i32(t3, arg2, 31);
+ tcg_gen_and_i32(t2, t2, arg2);
+ tcg_gen_and_i32(t3, t3, arg1);
+ tcg_gen_sub_i32(rh, t1, t2);
+ tcg_gen_sub_i32(rh, rh, t3);
+ tcg_gen_mov_i32(rl, t0);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ tcg_gen_ext_i32_i64(t0, arg1);
+ tcg_gen_ext_i32_i64(t1, arg2);
+ tcg_gen_mul_i64(t0, t0, t1);
+ tcg_gen_extr_i64_i32(rl, rh, t0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ }
+}
+
+static inline void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al,
+ TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
+{
+ if (TCG_TARGET_HAS_add2_i64) {
+ tcg_gen_op6_i64(INDEX_op_add2_i64, rl, rh, al, ah, bl, bh);
+ /* Allow the optimizer room to replace add2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ tcg_gen_add_i64(t0, al, bl);
+ tcg_gen_setcond_i64(TCG_COND_LTU, t1, t0, al);
+ tcg_gen_add_i64(rh, ah, bh);
+ tcg_gen_add_i64(rh, rh, t1);
+ tcg_gen_mov_i64(rl, t0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ }
+}
+
+static inline void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al,
+ TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
+{
+ if (TCG_TARGET_HAS_sub2_i64) {
+ tcg_gen_op6_i64(INDEX_op_sub2_i64, rl, rh, al, ah, bl, bh);
+ /* Allow the optimizer room to replace sub2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ tcg_gen_sub_i64(t0, al, bl);
+ tcg_gen_setcond_i64(TCG_COND_LTU, t1, al, bl);
+ tcg_gen_sub_i64(rh, ah, bh);
+ tcg_gen_sub_i64(rh, rh, t1);
+ tcg_gen_mov_i64(rl, t0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ }
+}
+
+static inline void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh,
+ TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ if (TCG_TARGET_HAS_mulu2_i64) {
+ tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2);
+ /* Allow the optimizer room to replace mulu2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ } else if (TCG_TARGET_HAS_mulu2_i64) {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ TCGv_i64 t3 = tcg_temp_new_i64();
+ tcg_gen_op4_i64(INDEX_op_mulu2_i64, t0, t1, arg1, arg2);
+ /* Allow the optimizer room to replace mulu2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ /* Adjust for negative inputs. */
+ tcg_gen_sari_i64(t2, arg1, 63);
+ tcg_gen_sari_i64(t3, arg2, 63);
+ tcg_gen_and_i64(t2, t2, arg2);
+ tcg_gen_and_i64(t3, t3, arg1);
+ tcg_gen_sub_i64(rh, t1, t2);
+ tcg_gen_sub_i64(rh, rh, t3);
+ tcg_gen_mov_i64(rl, t0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
+ tcg_temp_free_i64(t3);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and unsigned. */
+ sizemask |= tcg_gen_sizemask(0, 1, 0);
+ sizemask |= tcg_gen_sizemask(1, 1, 0);
+ sizemask |= tcg_gen_sizemask(2, 1, 0);
+ tcg_gen_mul_i64(t0, arg1, arg2);
+ tcg_gen_helper64(tcg_helper_muluh_i64, sizemask, rh, arg1, arg2);
+ tcg_gen_mov_i64(rl, t0);
+ tcg_temp_free_i64(t0);
+ }
+}
+
+static inline void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh,
+ TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ if (TCG_TARGET_HAS_muls2_i64) {
+ tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2);
+ /* Allow the optimizer room to replace muls2 with two moves. */
+ tcg_gen_op0(INDEX_op_nop);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 1, 1);
+ sizemask |= tcg_gen_sizemask(1, 1, 1);
+ sizemask |= tcg_gen_sizemask(2, 1, 1);
+ tcg_gen_mul_i64(t0, arg1, arg2);
+ tcg_gen_helper64(tcg_helper_mulsh_i64, sizemask, rh, arg1, arg2);
+ tcg_gen_mov_i64(rl, t0);
+ tcg_temp_free_i64(t0);
+ }
+}
+
/***************************************/
/* QEMU specific operations. Their type depend on the QEMU CPU
type. */
@@ -2625,6 +2843,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
#define tcg_gen_bswap32_tl tcg_gen_bswap32_i64
#define tcg_gen_bswap64_tl tcg_gen_bswap64_i64
#define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64
+#define tcg_gen_extr_i64_tl tcg_gen_extr32_i64
#define tcg_gen_andc_tl tcg_gen_andc_i64
#define tcg_gen_eqv_tl tcg_gen_eqv_i64
#define tcg_gen_nand_tl tcg_gen_nand_i64
@@ -2638,6 +2857,10 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
#define tcg_const_tl tcg_const_i64
#define tcg_const_local_tl tcg_const_local_i64
#define tcg_gen_movcond_tl tcg_gen_movcond_i64
+#define tcg_gen_add2_tl tcg_gen_add2_i64
+#define tcg_gen_sub2_tl tcg_gen_sub2_i64
+#define tcg_gen_mulu2_tl tcg_gen_mulu2_i64
+#define tcg_gen_muls2_tl tcg_gen_muls2_i64
#else
#define tcg_gen_movi_tl tcg_gen_movi_i32
#define tcg_gen_mov_tl tcg_gen_mov_i32
@@ -2697,6 +2920,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
#define tcg_gen_bswap16_tl tcg_gen_bswap16_i32
#define tcg_gen_bswap32_tl tcg_gen_bswap32_i32
#define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64
+#define tcg_gen_extr_tl_i64 tcg_gen_extr_i32_i64
#define tcg_gen_andc_tl tcg_gen_andc_i32
#define tcg_gen_eqv_tl tcg_gen_eqv_i32
#define tcg_gen_nand_tl tcg_gen_nand_i32
@@ -2710,6 +2934,10 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
#define tcg_const_tl tcg_const_i32
#define tcg_const_local_tl tcg_const_local_i32
#define tcg_gen_movcond_tl tcg_gen_movcond_i32
+#define tcg_gen_add2_tl tcg_gen_add2_i32
+#define tcg_gen_sub2_tl tcg_gen_sub2_i32
+#define tcg_gen_mulu2_tl tcg_gen_mulu2_i32
+#define tcg_gen_muls2_tl tcg_gen_muls2_i32
#endif
#if TCG_TARGET_REG_BITS == 32
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 9651063414..4246e9c1fa 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -83,10 +83,11 @@ DEF(deposit_i32, 1, 2, 2, IMPL(TCG_TARGET_HAS_deposit_i32))
DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END)
-DEF(add2_i32, 2, 4, 0, IMPL(TCG_TARGET_REG_BITS == 32))
-DEF(sub2_i32, 2, 4, 0, IMPL(TCG_TARGET_REG_BITS == 32))
+DEF(add2_i32, 2, 4, 0, IMPL(TCG_TARGET_HAS_add2_i32))
+DEF(sub2_i32, 2, 4, 0, IMPL(TCG_TARGET_HAS_sub2_i32))
+DEF(mulu2_i32, 2, 2, 0, IMPL(TCG_TARGET_HAS_mulu2_i32))
+DEF(muls2_i32, 2, 2, 0, IMPL(TCG_TARGET_HAS_muls2_i32))
DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | IMPL(TCG_TARGET_REG_BITS == 32))
-DEF(mulu2_i32, 2, 2, 0, IMPL(TCG_TARGET_REG_BITS == 32))
DEF(setcond2_i32, 1, 4, 1, IMPL(TCG_TARGET_REG_BITS == 32))
DEF(ext8s_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ext8s_i32))
@@ -158,6 +159,11 @@ DEF(eqv_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_eqv_i64))
DEF(nand_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_nand_i64))
DEF(nor_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_nor_i64))
+DEF(add2_i64, 2, 4, 0, IMPL64 | IMPL(TCG_TARGET_HAS_add2_i64))
+DEF(sub2_i64, 2, 4, 0, IMPL64 | IMPL(TCG_TARGET_HAS_sub2_i64))
+DEF(mulu2_i64, 2, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_mulu2_i64))
+DEF(muls2_i64, 2, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_muls2_i64))
+
/* QEMU specific */
#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
DEF(debug_insn_start, 0, 0, 2, 0)
diff --git a/tcg/tcg-runtime.h b/tcg/tcg-runtime.h
index 5615b133e0..a1ebef9f9c 100644
--- a/tcg/tcg-runtime.h
+++ b/tcg/tcg-runtime.h
@@ -12,7 +12,9 @@ int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2);
int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2);
int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2);
int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2);
+int64_t tcg_helper_mulsh_i64(int64_t arg1, int64_t arg2);
uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2);
uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2);
+uint64_t tcg_helper_muluh_i64(uint64_t arg1, uint64_t arg2);
#endif
diff --git a/tcg/tcg.c b/tcg/tcg.c
index c8a843ed09..1d8265e72e 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1217,7 +1217,7 @@ static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps,
static void tcg_liveness_analysis(TCGContext *s)
{
int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
- TCGOpcode op;
+ TCGOpcode op, op_new;
TCGArg *args;
const TCGOpDef *def;
uint8_t *dead_temps, *mem_temps;
@@ -1324,7 +1324,17 @@ static void tcg_liveness_analysis(TCGContext *s)
break;
case INDEX_op_add2_i32:
+ op_new = INDEX_op_add_i32;
+ goto do_addsub2;
case INDEX_op_sub2_i32:
+ op_new = INDEX_op_sub_i32;
+ goto do_addsub2;
+ case INDEX_op_add2_i64:
+ op_new = INDEX_op_add_i64;
+ goto do_addsub2;
+ case INDEX_op_sub2_i64:
+ op_new = INDEX_op_sub_i64;
+ do_addsub2:
args -= 6;
nb_iargs = 4;
nb_oargs = 2;
@@ -1337,12 +1347,7 @@ static void tcg_liveness_analysis(TCGContext *s)
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;
- }
- s->gen_opc_buf[op_index] = op;
+ s->gen_opc_buf[op_index] = op = op_new;
args[1] = args[2];
args[2] = args[4];
assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
@@ -1354,6 +1359,13 @@ static void tcg_liveness_analysis(TCGContext *s)
goto do_not_remove;
case INDEX_op_mulu2_i32:
+ case INDEX_op_muls2_i32:
+ op_new = INDEX_op_mul_i32;
+ goto do_mul2;
+ case INDEX_op_mulu2_i64:
+ case INDEX_op_muls2_i64:
+ op_new = INDEX_op_mul_i64;
+ do_mul2:
args -= 4;
nb_iargs = 2;
nb_oargs = 2;
@@ -1362,7 +1374,7 @@ static void tcg_liveness_analysis(TCGContext *s)
if (dead_temps[args[0]] && !mem_temps[args[0]]) {
goto do_remove;
}
- s->gen_opc_buf[op_index] = op = INDEX_op_mul_i32;
+ s->gen_opc_buf[op_index] = op = op_new;
args[1] = args[2];
args[2] = args[3];
assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 51c8176550..b195396b0f 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -57,8 +57,8 @@ typedef uint64_t TCGRegSet;
#error unsupported
#endif
-/* Turn some undef macros into false macros. */
#if TCG_TARGET_REG_BITS == 32
+/* Turn some undef macros into false macros. */
#define TCG_TARGET_HAS_div_i64 0
#define TCG_TARGET_HAS_div2_i64 0
#define TCG_TARGET_HAS_rot_i64 0
@@ -80,6 +80,14 @@ typedef uint64_t TCGRegSet;
#define TCG_TARGET_HAS_nor_i64 0
#define TCG_TARGET_HAS_deposit_i64 0
#define TCG_TARGET_HAS_movcond_i64 0
+#define TCG_TARGET_HAS_add2_i64 0
+#define TCG_TARGET_HAS_sub2_i64 0
+#define TCG_TARGET_HAS_mulu2_i64 0
+#define TCG_TARGET_HAS_muls2_i64 0
+/* Turn some undef macros into true macros. */
+#define TCG_TARGET_HAS_add2_i32 1
+#define TCG_TARGET_HAS_sub2_i32 1
+#define TCG_TARGET_HAS_mulu2_i32 1
#endif
#ifndef TCG_TARGET_deposit_i32_valid
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index a832f5cf52..1f17576f54 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -76,6 +76,7 @@
#define TCG_TARGET_HAS_orc_i32 0
#define TCG_TARGET_HAS_rot_i32 1
#define TCG_TARGET_HAS_movcond_i32 0
+#define TCG_TARGET_HAS_muls2_i32 0
#if TCG_TARGET_REG_BITS == 64
#define TCG_TARGET_HAS_bswap16_i64 1
@@ -100,6 +101,14 @@
#define TCG_TARGET_HAS_orc_i64 0
#define TCG_TARGET_HAS_rot_i64 1
#define TCG_TARGET_HAS_movcond_i64 0
+#define TCG_TARGET_HAS_muls2_i64 0
+
+#define TCG_TARGET_HAS_add2_i32 0
+#define TCG_TARGET_HAS_sub2_i32 0
+#define TCG_TARGET_HAS_mulu2_i32 0
+#define TCG_TARGET_HAS_add2_i64 0
+#define TCG_TARGET_HAS_sub2_i64 0
+#define TCG_TARGET_HAS_mulu2_i64 0
#endif /* TCG_TARGET_REG_BITS == 64 */
/* Number of registers available.
diff --git a/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c b/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c
index 669405faf1..7ba633bc17 100644
--- a/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c
+++ b/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c
@@ -8,7 +8,7 @@ int main()
rs = 0x80001234;
rt = 0x80004321;
- result = 0x80005555;
+ result = 0x7FFFAAAB;
__asm
("mulq_rs.w %0, %1, %2\n\t"
diff --git a/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c b/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c
index d0f7674a38..00e015542e 100644
--- a/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c
+++ b/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c
@@ -6,6 +6,21 @@ int main()
int rd, rs, rt, dsp;
int result, resultdsp;
+ rs = 0x80000000;
+ rt = 0x0ffc0000;
+ result = 0xF0040000;
+ resultdsp = 0;
+
+ __asm
+ ("mulq_s.ph %0, %2, %3\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rd), "=r"(dsp)
+ : "r"(rs), "r"(rt)
+ );
+ dsp = (dsp >> 21) & 0x01;
+ assert(rd == result);
+ assert(dsp == resultdsp);
+
rs = 0x80001234;
rt = 0x80004321;
result = 0x7FFF098B;
diff --git a/tests/tcg/mips/mips32-dspr2/mulq_s_w.c b/tests/tcg/mips/mips32-dspr2/mulq_s_w.c
index df148b7ffb..9c2be06cc0 100644
--- a/tests/tcg/mips/mips32-dspr2/mulq_s_w.c
+++ b/tests/tcg/mips/mips32-dspr2/mulq_s_w.c
@@ -8,7 +8,7 @@ int main()
rs = 0x80001234;
rt = 0x80004321;
- result = 0x80005555;
+ result = 0x7FFFAAAB;
__asm
("mulq_s.w %0, %1, %2\n\t"
diff --git a/tests/tcg/test-i386.c b/tests/tcg/test-i386.c
index 6dc730d882..b05572b734 100644
--- a/tests/tcg/test-i386.c
+++ b/tests/tcg/test-i386.c
@@ -209,7 +209,7 @@ static inline long i2l(long v)
#define TEST_LEA16(STR)\
{\
asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\
- : "=wq" (res)\
+ : "=r" (res)\
: "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
printf("lea %s = %08lx\n", STR, res);\
}
@@ -925,7 +925,7 @@ void test_fbcd(double a)
void test_fenv(void)
{
- struct QEMU_PACKED {
+ struct __attribute__((__packed__)) {
uint16_t fpuc;
uint16_t dummy1;
uint16_t fpus;
@@ -935,7 +935,7 @@ void test_fenv(void)
uint32_t ignored[4];
long double fpregs[8];
} float_env32;
- struct QEMU_PACKED {
+ struct __attribute__((__packed__)) {
uint16_t fpuc;
uint16_t fpus;
uint16_t fptag;
@@ -1280,7 +1280,7 @@ void test_segs(void)
struct {
uint32_t offset;
uint16_t seg;
- } QEMU_PACKED segoff;
+ } __attribute__((__packed__)) segoff;
ldt.entry_number = 1;
ldt.base_addr = (unsigned long)&seg_data1;
@@ -1828,7 +1828,7 @@ void test_exceptions(void)
printf("lock nop exception:\n");
if (setjmp(jmp_env) == 0) {
/* now execute an invalid instruction */
- asm volatile(".byte 0xf0, 0x90"); /* lock nop */
+ asm volatile(".byte 0xf0, 0x90");
}
printf("INT exception:\n");
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index d9db073584..85c50cd89b 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -13,7 +13,10 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
common-obj-$(CONFIG_COCOA) += cocoa.o
common-obj-$(CONFIG_CURSES) += curses.o
common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
+common-obj-$(CONFIG_GTK) += gtk.o
$(obj)/sdl.o $(obj)/sdl_zoom.o: QEMU_CFLAGS += $(SDL_CFLAGS)
$(obj)/cocoa.o: $(SRC_PATH)/$(obj)/cocoa.m
+
+$(obj)/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)
diff --git a/ui/console.c b/ui/console.c
index 0a68836d50..0d95f32123 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1339,11 +1339,16 @@ DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
}
DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
- int linesize, uint8_t *data)
+ int linesize, uint8_t *data,
+ bool byteswap)
{
DisplaySurface *surface = g_new0(DisplaySurface, 1);
- surface->pf = qemu_default_pixelformat(bpp);
+ if (byteswap) {
+ surface->pf = qemu_different_endianness_pixelformat(bpp);
+ } else {
+ surface->pf = qemu_default_pixelformat(bpp);
+ }
surface->format = qemu_pixman_get_format(&surface->pf);
assert(surface->format != 0);
@@ -1532,7 +1537,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
chr->init(chr);
}
-CharDriverState *text_console_init(QemuOpts *opts)
+static CharDriverState *text_console_init(QemuOpts *opts)
{
CharDriverState *chr;
QemuConsole *s;
@@ -1568,6 +1573,18 @@ CharDriverState *text_console_init(QemuOpts *opts)
return chr;
}
+static VcHandler *vc_handler = text_console_init;
+
+CharDriverState *vc_init(QemuOpts *opts)
+{
+ return vc_handler(opts);
+}
+
+void register_vc_handler(VcHandler *handler)
+{
+ vc_handler = handler;
+}
+
void text_consoles_set_display(DisplayState *ds)
{
int i;
diff --git a/ui/gtk.c b/ui/gtk.c
new file mode 100644
index 0000000000..dcce36d243
--- /dev/null
+++ b/ui/gtk.c
@@ -0,0 +1,1217 @@
+/*
+ * GTK UI
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Portions from gtk-vnc:
+ *
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define GETTEXT_PACKAGE "qemu"
+#define LOCALEDIR "po"
+
+#include "qemu-common.h"
+
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+/* Work around an -Wstrict-prototypes warning in GTK headers */
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#endif
+#include <gtk/gtk.h>
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+#pragma GCC diagnostic error "-Wstrict-prototypes"
+#endif
+
+
+#include <gdk/gdkkeysyms.h>
+#include <glib/gi18n.h>
+#include <locale.h>
+#include <vte/vte.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <pty.h>
+#include <math.h>
+
+#include "ui/console.h"
+#include "sysemu/sysemu.h"
+#include "qmp-commands.h"
+#include "x_keymap.h"
+#include "keymaps.h"
+#include "char/char.h"
+
+//#define DEBUG_GTK
+
+#ifdef DEBUG_GTK
+#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define MAX_VCS 10
+
+typedef struct VirtualConsole
+{
+ GtkWidget *menu_item;
+ GtkWidget *terminal;
+ GtkWidget *scrolled_window;
+ CharDriverState *chr;
+ int fd;
+} VirtualConsole;
+
+typedef struct GtkDisplayState
+{
+ GtkWidget *window;
+
+ GtkWidget *menu_bar;
+
+ GtkAccelGroup *accel_group;
+
+ GtkWidget *machine_menu_item;
+ GtkWidget *machine_menu;
+ GtkWidget *pause_item;
+ GtkWidget *reset_item;
+ GtkWidget *powerdown_item;
+ GtkWidget *quit_item;
+
+ GtkWidget *view_menu_item;
+ GtkWidget *view_menu;
+ GtkWidget *full_screen_item;
+ GtkWidget *zoom_in_item;
+ GtkWidget *zoom_out_item;
+ GtkWidget *zoom_fixed_item;
+ GtkWidget *zoom_fit_item;
+ GtkWidget *grab_item;
+ GtkWidget *grab_on_hover_item;
+ GtkWidget *vga_item;
+
+ int nb_vcs;
+ VirtualConsole vc[MAX_VCS];
+
+ GtkWidget *show_tabs_item;
+
+ GtkWidget *vbox;
+ GtkWidget *notebook;
+ GtkWidget *drawing_area;
+ cairo_surface_t *surface;
+ DisplayChangeListener dcl;
+ DisplayState *ds;
+ int button_mask;
+ int last_x;
+ int last_y;
+
+ double scale_x;
+ double scale_y;
+ gboolean full_screen;
+
+ GdkCursor *null_cursor;
+ Notifier mouse_mode_notifier;
+ gboolean free_scale;
+
+ bool external_pause_update;
+} GtkDisplayState;
+
+static GtkDisplayState *global_state;
+
+/** Utility Functions **/
+
+static bool gd_is_grab_active(GtkDisplayState *s)
+{
+ return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_item));
+}
+
+static bool gd_grab_on_hover(GtkDisplayState *s)
+{
+ return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_on_hover_item));
+}
+
+static bool gd_on_vga(GtkDisplayState *s)
+{
+ return gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0;
+}
+
+static void gd_update_cursor(GtkDisplayState *s, gboolean override)
+{
+ GdkWindow *window;
+ bool on_vga;
+
+ window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
+
+ on_vga = gd_on_vga(s);
+
+ if ((override || on_vga) &&
+ (s->full_screen || kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
+ gdk_window_set_cursor(window, s->null_cursor);
+ } else {
+ gdk_window_set_cursor(window, NULL);
+ }
+}
+
+static void gd_update_caption(GtkDisplayState *s)
+{
+ const char *status = "";
+ gchar *title;
+ const char *grab = "";
+ bool is_paused = !runstate_is_running();
+
+ if (gd_is_grab_active(s)) {
+ grab = " - Press Ctrl+Alt+G to release grab";
+ }
+
+ if (is_paused) {
+ status = " [Paused]";
+ }
+ s->external_pause_update = true;
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->pause_item),
+ is_paused);
+ s->external_pause_update = false;
+
+ if (qemu_name) {
+ title = g_strdup_printf("QEMU (%s)%s%s", qemu_name, status, grab);
+ } else {
+ title = g_strdup_printf("QEMU%s%s", status, grab);
+ }
+
+ gtk_window_set_title(GTK_WINDOW(s->window), title);
+
+ g_free(title);
+}
+
+/** DisplayState Callbacks **/
+
+static void gd_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ GtkDisplayState *s = ds->opaque;
+ int x1, x2, y1, y2;
+ int mx, my;
+ int fbw, fbh;
+ int ww, wh;
+
+ DPRINTF("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
+
+ x1 = floor(x * s->scale_x);
+ y1 = floor(y * s->scale_y);
+
+ x2 = ceil(x * s->scale_x + w * s->scale_x);
+ y2 = ceil(y * s->scale_y + h * s->scale_y);
+
+ fbw = ds_get_width(s->ds) * s->scale_x;
+ fbh = ds_get_height(s->ds) * s->scale_y;
+
+ gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+
+ mx = my = 0;
+ if (ww > fbw) {
+ mx = (ww - fbw) / 2;
+ }
+ if (wh > fbh) {
+ my = (wh - fbh) / 2;
+ }
+
+ gtk_widget_queue_draw_area(s->drawing_area, mx + x1, my + y1, (x2 - x1), (y2 - y1));
+}
+
+static void gd_refresh(DisplayState *ds)
+{
+ vga_hw_update();
+}
+
+static void gd_resize(DisplayState *ds)
+{
+ GtkDisplayState *s = ds->opaque;
+ cairo_format_t kind;
+ int stride;
+
+ DPRINTF("resize(width=%d, height=%d)\n",
+ ds_get_width(ds), ds_get_height(ds));
+
+ if (s->surface) {
+ cairo_surface_destroy(s->surface);
+ }
+
+ switch (ds->surface->pf.bits_per_pixel) {
+ case 8:
+ kind = CAIRO_FORMAT_A8;
+ break;
+ case 16:
+ kind = CAIRO_FORMAT_RGB16_565;
+ break;
+ case 32:
+ kind = CAIRO_FORMAT_RGB24;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ stride = cairo_format_stride_for_width(kind, ds_get_width(ds));
+ g_assert(ds_get_linesize(ds) == stride);
+
+ s->surface = cairo_image_surface_create_for_data(ds_get_data(ds),
+ kind,
+ ds_get_width(ds),
+ ds_get_height(ds),
+ ds_get_linesize(ds));
+
+ if (!s->full_screen) {
+ GtkRequisition req;
+ double sx, sy;
+
+ if (s->free_scale) {
+ sx = s->scale_x;
+ sy = s->scale_y;
+
+ s->scale_y = 1.0;
+ s->scale_x = 1.0;
+ } else {
+ sx = 1.0;
+ sy = 1.0;
+ }
+
+ gtk_widget_set_size_request(s->drawing_area,
+ ds_get_width(ds) * s->scale_x,
+ ds_get_height(ds) * s->scale_y);
+ gtk_widget_size_request(s->vbox, &req);
+
+ gtk_window_resize(GTK_WINDOW(s->window),
+ req.width * sx, req.height * sy);
+ }
+}
+
+/** QEMU Events **/
+
+static void gd_change_runstate(void *opaque, int running, RunState state)
+{
+ GtkDisplayState *s = opaque;
+
+ gd_update_caption(s);
+}
+
+static void gd_mouse_mode_change(Notifier *notify, void *data)
+{
+ gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
+ FALSE);
+}
+
+/** GTK Events **/
+
+static gboolean gd_window_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+ GtkAccelGroupEntry *entries;
+ guint n_entries = 0;
+ gboolean propagate_accel = TRUE;
+ gboolean handled = FALSE;
+
+ entries = gtk_accel_group_query(s->accel_group, key->keyval,
+ key->state, &n_entries);
+ if (n_entries) {
+ const char *quark = g_quark_to_string(entries[0].accel_path_quark);
+
+ if (gd_is_grab_active(s) && strstart(quark, "<QEMU>/File/", NULL)) {
+ propagate_accel = FALSE;
+ }
+ }
+
+ if (!handled && propagate_accel) {
+ handled = gtk_window_activate_key(GTK_WINDOW(widget), key);
+ }
+
+ if (!handled) {
+ handled = gtk_window_propagate_key_event(GTK_WINDOW(widget), key);
+ }
+
+ return handled;
+}
+
+static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
+ void *opaque)
+{
+ GtkDisplayState *s = opaque;
+
+ if (!no_quit) {
+ unregister_displaychangelistener(s->ds, &s->dcl);
+ qmp_quit(NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+ int mx, my;
+ int ww, wh;
+ int fbw, fbh;
+
+ if (!gtk_widget_get_realized(widget)) {
+ return FALSE;
+ }
+
+ fbw = ds_get_width(s->ds);
+ fbh = ds_get_height(s->ds);
+
+ gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
+
+ if (s->full_screen) {
+ s->scale_x = (double)ww / fbw;
+ s->scale_y = (double)wh / fbh;
+ } else if (s->free_scale) {
+ double sx, sy;
+
+ sx = (double)ww / fbw;
+ sy = (double)wh / fbh;
+
+ s->scale_x = s->scale_y = MIN(sx, sy);
+ }
+
+ fbw *= s->scale_x;
+ fbh *= s->scale_y;
+
+ mx = my = 0;
+ if (ww > fbw) {
+ mx = (ww - fbw) / 2;
+ }
+ if (wh > fbh) {
+ my = (wh - fbh) / 2;
+ }
+
+ cairo_rectangle(cr, 0, 0, ww, wh);
+
+ /* Optionally cut out the inner area where the pixmap
+ will be drawn. This avoids 'flashing' since we're
+ not double-buffering. Note we're using the undocumented
+ behaviour of drawing the rectangle from right to left
+ to cut out the whole */
+ cairo_rectangle(cr, mx + fbw, my,
+ -1 * fbw, fbh);
+ cairo_fill(cr);
+
+ cairo_scale(cr, s->scale_x, s->scale_y);
+ cairo_set_source_surface(cr, s->surface, mx / s->scale_x, my / s->scale_y);
+ cairo_paint(cr);
+
+ return TRUE;
+}
+
+static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
+ void *opaque)
+{
+ cairo_t *cr;
+ gboolean ret;
+
+ cr = gdk_cairo_create(gtk_widget_get_window(widget));
+ cairo_rectangle(cr,
+ expose->area.x,
+ expose->area.y,
+ expose->area.width,
+ expose->area.height);
+ cairo_clip(cr);
+
+ ret = gd_draw_event(widget, cr, opaque);
+
+ cairo_destroy(cr);
+
+ return ret;
+}
+
+static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
+ void *opaque)
+{
+ GtkDisplayState *s = opaque;
+ int dx, dy;
+ int x, y;
+ int mx, my;
+ int fbh, fbw;
+ int ww, wh;
+
+ fbw = ds_get_width(s->ds) * s->scale_x;
+ fbh = ds_get_height(s->ds) * s->scale_y;
+
+ gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+
+ mx = my = 0;
+ if (ww > fbw) {
+ mx = (ww - fbw) / 2;
+ }
+ if (wh > fbh) {
+ my = (wh - fbh) / 2;
+ }
+
+ x = (motion->x - mx) / s->scale_x;
+ y = (motion->y - my) / s->scale_y;
+
+ if (x < 0 || y < 0 ||
+ x >= ds_get_width(s->ds) ||
+ y >= ds_get_height(s->ds)) {
+ return TRUE;
+ }
+
+ if (kbd_mouse_is_absolute()) {
+ dx = x * 0x7FFF / (ds_get_width(s->ds) - 1);
+ dy = y * 0x7FFF / (ds_get_height(s->ds) - 1);
+ } else if (s->last_x == -1 || s->last_y == -1) {
+ dx = 0;
+ dy = 0;
+ } else {
+ dx = x - s->last_x;
+ dy = y - s->last_y;
+ }
+
+ s->last_x = x;
+ s->last_y = y;
+
+ if (kbd_mouse_is_absolute() || gd_is_grab_active(s)) {
+ kbd_mouse_event(dx, dy, 0, s->button_mask);
+ }
+
+ if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) {
+ GdkDrawable *drawable = GDK_DRAWABLE(gtk_widget_get_window(s->drawing_area));
+ GdkDisplay *display = gdk_drawable_get_display(drawable);
+ GdkScreen *screen = gdk_drawable_get_screen(drawable);
+ int x = (int)motion->x_root;
+ int y = (int)motion->y_root;
+
+ /* In relative mode check to see if client pointer hit
+ * one of the screen edges, and if so move it back by
+ * 200 pixels. This is important because the pointer
+ * in the server doesn't correspond 1-for-1, and so
+ * may still be only half way across the screen. Without
+ * this warp, the server pointer would thus appear to hit
+ * an invisible wall */
+ if (x == 0) {
+ x += 200;
+ }
+ if (y == 0) {
+ y += 200;
+ }
+ if (x == (gdk_screen_get_width(screen) - 1)) {
+ x -= 200;
+ }
+ if (y == (gdk_screen_get_height(screen) - 1)) {
+ y -= 200;
+ }
+
+ if (x != (int)motion->x_root || y != (int)motion->y_root) {
+ gdk_display_warp_pointer(display, screen, x, y);
+ s->last_x = -1;
+ s->last_y = -1;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
+ void *opaque)
+{
+ GtkDisplayState *s = opaque;
+ int dx, dy;
+ int n;
+
+ if (button->button == 1) {
+ n = 0x01;
+ } else if (button->button == 2) {
+ n = 0x04;
+ } else if (button->button == 3) {
+ n = 0x02;
+ } else {
+ n = 0x00;
+ }
+
+ if (button->type == GDK_BUTTON_PRESS) {
+ s->button_mask |= n;
+ } else if (button->type == GDK_BUTTON_RELEASE) {
+ s->button_mask &= ~n;
+ }
+
+ if (kbd_mouse_is_absolute()) {
+ dx = s->last_x * 0x7FFF / (ds_get_width(s->ds) - 1);
+ dy = s->last_y * 0x7FFF / (ds_get_height(s->ds) - 1);
+ } else {
+ dx = 0;
+ dy = 0;
+ }
+
+ kbd_mouse_event(dx, dy, 0, s->button_mask);
+
+ return TRUE;
+}
+
+static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
+{
+ int gdk_keycode;
+ int qemu_keycode;
+
+ gdk_keycode = key->hardware_keycode;
+
+ if (gdk_keycode < 9) {
+ qemu_keycode = 0;
+ } else if (gdk_keycode < 97) {
+ qemu_keycode = gdk_keycode - 8;
+ } else if (gdk_keycode < 158) {
+ qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
+ } else if (gdk_keycode == 208) { /* Hiragana_Katakana */
+ qemu_keycode = 0x70;
+ } else if (gdk_keycode == 211) { /* backslash */
+ qemu_keycode = 0x73;
+ } else {
+ qemu_keycode = 0;
+ }
+
+ DPRINTF("translated GDK keycode %d to QEMU keycode %d (%s)\n",
+ gdk_keycode, qemu_keycode,
+ (key->type == GDK_KEY_PRESS) ? "down" : "up");
+
+ if (qemu_keycode & SCANCODE_GREY) {
+ kbd_put_keycode(SCANCODE_EMUL0);
+ }
+
+ if (key->type == GDK_KEY_PRESS) {
+ kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
+ } else if (key->type == GDK_KEY_RELEASE) {
+ kbd_put_keycode(qemu_keycode | SCANCODE_UP);
+ } else {
+ g_assert_not_reached();
+ }
+
+ return TRUE;
+}
+
+/** Window Menu Actions **/
+
+static void gd_menu_pause(GtkMenuItem *item, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+
+ if (s->external_pause_update) {
+ return;
+ }
+ if (runstate_is_running()) {
+ qmp_stop(NULL);
+ } else {
+ qmp_cont(NULL);
+ }
+}
+
+static void gd_menu_reset(GtkMenuItem *item, void *opaque)
+{
+ qmp_system_reset(NULL);
+}
+
+static void gd_menu_powerdown(GtkMenuItem *item, void *opaque)
+{
+ qmp_system_powerdown(NULL);
+}
+
+static void gd_menu_quit(GtkMenuItem *item, void *opaque)
+{
+ qmp_quit(NULL);
+}
+
+static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
+ } else {
+ int i;
+
+ for (i = 0; i < s->nb_vcs; i++) {
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vc[i].menu_item))) {
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), i + 1);
+ break;
+ }
+ }
+ }
+}
+
+static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) {
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE);
+ } else {
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
+ }
+}
+
+static void gd_menu_full_screen(GtkMenuItem *item, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+
+ if (!s->full_screen) {
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
+ gtk_widget_set_size_request(s->menu_bar, 0, 0);
+ gtk_widget_set_size_request(s->drawing_area, -1, -1);
+ gtk_window_fullscreen(GTK_WINDOW(s->window));
+ if (gd_on_vga(s)) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE);
+ }
+ s->full_screen = TRUE;
+ } else {
+ gtk_window_unfullscreen(GTK_WINDOW(s->window));
+ gd_menu_show_tabs(GTK_MENU_ITEM(s->show_tabs_item), s);
+ gtk_widget_set_size_request(s->menu_bar, -1, -1);
+ gtk_widget_set_size_request(s->drawing_area,
+ ds_get_width(s->ds), ds_get_height(s->ds));
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE);
+ s->full_screen = FALSE;
+ s->scale_x = 1.0;
+ s->scale_y = 1.0;
+ }
+
+ gd_update_cursor(s, FALSE);
+}
+
+static void gd_menu_zoom_in(GtkMenuItem *item, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item),
+ FALSE);
+
+ s->scale_x += .25;
+ s->scale_y += .25;
+
+ gd_resize(s->ds);
+}
+
+static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item),
+ FALSE);
+
+ s->scale_x -= .25;
+ s->scale_y -= .25;
+
+ s->scale_x = MAX(s->scale_x, .25);
+ s->scale_y = MAX(s->scale_y, .25);
+
+ gd_resize(s->ds);
+}
+
+static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+
+ s->scale_x = 1.0;
+ s->scale_y = 1.0;
+
+ gd_resize(s->ds);
+}
+
+static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+ int ww, wh;
+
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item))) {
+ s->free_scale = TRUE;
+ } else {
+ s->free_scale = FALSE;
+ }
+
+ gd_resize(s->ds);
+
+ gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+ gtk_widget_queue_draw_area(s->drawing_area, 0, 0, ww, wh);
+}
+
+static void gd_grab_keyboard(GtkDisplayState *s)
+{
+ gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)),
+ FALSE,
+ GDK_CURRENT_TIME);
+}
+
+static void gd_ungrab_keyboard(GtkDisplayState *s)
+{
+ gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+}
+
+static void gd_menu_grab_input(GtkMenuItem *item, void *opaque)
+{
+ GtkDisplayState *s = opaque;
+
+ if (gd_is_grab_active(s)) {
+ gd_grab_keyboard(s);
+ gdk_pointer_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)),
+ FALSE, /* All events to come to our window directly */
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_SCROLL_MASK,
+ NULL, /* Allow cursor to move over entire desktop */
+ s->null_cursor,
+ GDK_CURRENT_TIME);
+ } else {
+ gd_ungrab_keyboard(s);
+ gdk_pointer_ungrab(GDK_CURRENT_TIME);
+ }
+
+ gd_update_caption(s);
+ gd_update_cursor(s, FALSE);
+}
+
+static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
+ gpointer data)
+{
+ GtkDisplayState *s = data;
+ guint last_page;
+ gboolean on_vga;
+
+ if (!gtk_widget_get_realized(s->notebook)) {
+ return;
+ }
+
+ last_page = gtk_notebook_get_current_page(nb);
+
+ if (last_page) {
+ gtk_widget_set_size_request(s->vc[last_page - 1].terminal, -1, -1);
+ }
+
+ on_vga = arg2 == 0;
+
+ if (!on_vga) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+ FALSE);
+ } else if (s->full_screen) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+ TRUE);
+ }
+
+ if (arg2 == 0) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE);
+ } else {
+ VirtualConsole *vc = &s->vc[arg2 - 1];
+ VteTerminal *term = VTE_TERMINAL(vc->terminal);
+ int width, height;
+
+ width = 80 * vte_terminal_get_char_width(term);
+ height = 25 * vte_terminal_get_char_height(term);
+
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE);
+ gtk_widget_set_size_request(vc->terminal, width, height);
+ }
+
+ gtk_widget_set_sensitive(s->grab_item, on_vga);
+
+ gd_update_cursor(s, TRUE);
+}
+
+static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data)
+{
+ GtkDisplayState *s = data;
+
+ if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) {
+ gd_grab_keyboard(s);
+ }
+
+ return TRUE;
+}
+
+static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data)
+{
+ GtkDisplayState *s = data;
+
+ if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) {
+ gd_ungrab_keyboard(s);
+ }
+
+ return TRUE;
+}
+
+/** Virtual Console Callbacks **/
+
+static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ VirtualConsole *vc = chr->opaque;
+
+ return write(vc->fd, buf, len);
+}
+
+static int nb_vcs;
+static CharDriverState *vcs[MAX_VCS];
+
+static CharDriverState *gd_vc_handler(QemuOpts *opts)
+{
+ CharDriverState *chr;
+
+ chr = g_malloc0(sizeof(*chr));
+ chr->chr_write = gd_vc_chr_write;
+
+ vcs[nb_vcs++] = chr;
+
+ return chr;
+}
+
+void early_gtk_display_init(void)
+{
+ register_vc_handler(gd_vc_handler);
+}
+
+static gboolean gd_vc_in(GIOChannel *chan, GIOCondition cond, void *opaque)
+{
+ VirtualConsole *vc = opaque;
+ uint8_t buffer[1024];
+ ssize_t len;
+
+ len = read(vc->fd, buffer, sizeof(buffer));
+ if (len <= 0) {
+ return FALSE;
+ }
+
+ qemu_chr_be_write(vc->chr, buffer, len);
+
+ return TRUE;
+}
+
+static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSList *group)
+{
+ const char *label;
+ char buffer[32];
+ char path[32];
+#if VTE_CHECK_VERSION(0, 26, 0)
+ VtePty *pty;
+#endif
+ GIOChannel *chan;
+ GtkWidget *scrolled_window;
+ GtkAdjustment *vadjustment;
+ int master_fd, slave_fd, ret;
+ struct termios tty;
+
+ snprintf(buffer, sizeof(buffer), "vc%d", index);
+ snprintf(path, sizeof(path), "<QEMU>/View/VC%d", index);
+
+ vc->chr = vcs[index];
+
+ if (vc->chr->label) {
+ label = vc->chr->label;
+ } else {
+ label = buffer;
+ }
+
+ vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, label);
+ group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item));
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc->menu_item), path);
+ gtk_accel_map_add_entry(path, GDK_KEY_2 + index, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+
+ vc->terminal = vte_terminal_new();
+
+ ret = openpty(&master_fd, &slave_fd, NULL, NULL, NULL);
+ g_assert(ret != -1);
+
+ /* Set raw attributes on the pty. */
+ tcgetattr(slave_fd, &tty);
+ cfmakeraw(&tty);
+ tcsetattr(slave_fd, TCSAFLUSH, &tty);
+
+#if VTE_CHECK_VERSION(0, 26, 0)
+ pty = vte_pty_new_foreign(master_fd, NULL);
+ vte_terminal_set_pty_object(VTE_TERMINAL(vc->terminal), pty);
+#else
+ vte_terminal_set_pty(VTE_TERMINAL(vc->terminal), master_fd);
+#endif
+
+ vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->terminal), -1);
+
+ vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->terminal));
+
+ scrolled_window = gtk_scrolled_window_new(NULL, vadjustment);
+ gtk_container_add(GTK_CONTAINER(scrolled_window), vc->terminal);
+
+ vte_terminal_set_size(VTE_TERMINAL(vc->terminal), 80, 25);
+
+ vc->fd = slave_fd;
+ vc->chr->opaque = vc;
+ vc->scrolled_window = scrolled_window;
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vc->scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), scrolled_window, gtk_label_new(label));
+ g_signal_connect(vc->menu_item, "activate",
+ G_CALLBACK(gd_menu_switch_vc), s);
+
+ gtk_menu_append(GTK_MENU(s->view_menu), vc->menu_item);
+
+ qemu_chr_generic_open(vc->chr);
+ if (vc->chr->init) {
+ vc->chr->init(vc->chr);
+ }
+
+ chan = g_io_channel_unix_new(vc->fd);
+ g_io_add_watch(chan, G_IO_IN, gd_vc_in, vc);
+
+ return group;
+}
+
+/** Window Creation **/
+
+static void gd_connect_signals(GtkDisplayState *s)
+{
+ g_signal_connect(s->show_tabs_item, "activate",
+ G_CALLBACK(gd_menu_show_tabs), s);
+
+ g_signal_connect(s->window, "key-press-event",
+ G_CALLBACK(gd_window_key_event), s);
+ g_signal_connect(s->window, "delete-event",
+ G_CALLBACK(gd_window_close), s);
+
+ g_signal_connect(s->drawing_area, "expose-event",
+ G_CALLBACK(gd_expose_event), s);
+ g_signal_connect(s->drawing_area, "motion-notify-event",
+ G_CALLBACK(gd_motion_event), s);
+ g_signal_connect(s->drawing_area, "button-press-event",
+ G_CALLBACK(gd_button_event), s);
+ g_signal_connect(s->drawing_area, "button-release-event",
+ G_CALLBACK(gd_button_event), s);
+ g_signal_connect(s->drawing_area, "key-press-event",
+ G_CALLBACK(gd_key_event), s);
+ g_signal_connect(s->drawing_area, "key-release-event",
+ G_CALLBACK(gd_key_event), s);
+
+ g_signal_connect(s->pause_item, "activate",
+ G_CALLBACK(gd_menu_pause), s);
+ g_signal_connect(s->reset_item, "activate",
+ G_CALLBACK(gd_menu_reset), s);
+ g_signal_connect(s->powerdown_item, "activate",
+ G_CALLBACK(gd_menu_powerdown), s);
+ g_signal_connect(s->quit_item, "activate",
+ G_CALLBACK(gd_menu_quit), s);
+ g_signal_connect(s->full_screen_item, "activate",
+ G_CALLBACK(gd_menu_full_screen), s);
+ g_signal_connect(s->zoom_in_item, "activate",
+ G_CALLBACK(gd_menu_zoom_in), s);
+ g_signal_connect(s->zoom_out_item, "activate",
+ G_CALLBACK(gd_menu_zoom_out), s);
+ g_signal_connect(s->zoom_fixed_item, "activate",
+ G_CALLBACK(gd_menu_zoom_fixed), s);
+ g_signal_connect(s->zoom_fit_item, "activate",
+ G_CALLBACK(gd_menu_zoom_fit), s);
+ g_signal_connect(s->vga_item, "activate",
+ G_CALLBACK(gd_menu_switch_vc), s);
+ g_signal_connect(s->grab_item, "activate",
+ G_CALLBACK(gd_menu_grab_input), s);
+ g_signal_connect(s->notebook, "switch-page",
+ G_CALLBACK(gd_change_page), s);
+ g_signal_connect(s->drawing_area, "enter-notify-event",
+ G_CALLBACK(gd_enter_event), s);
+ g_signal_connect(s->drawing_area, "leave-notify-event",
+ G_CALLBACK(gd_leave_event), s);
+}
+
+static void gd_create_menus(GtkDisplayState *s)
+{
+ GtkStockItem item;
+ GtkAccelGroup *accel_group;
+ GSList *group = NULL;
+ GtkWidget *separator;
+ int i;
+
+ accel_group = gtk_accel_group_new();
+ s->machine_menu = gtk_menu_new();
+ gtk_menu_set_accel_group(GTK_MENU(s->machine_menu), accel_group);
+ s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine"));
+
+ s->pause_item = gtk_check_menu_item_new_with_mnemonic(_("_Pause"));
+ gtk_menu_append(GTK_MENU(s->machine_menu), s->pause_item);
+
+ separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(s->machine_menu), separator);
+
+ s->reset_item = gtk_image_menu_item_new_with_mnemonic(_("_Reset"));
+ gtk_menu_append(GTK_MENU(s->machine_menu), s->reset_item);
+
+ s->powerdown_item = gtk_image_menu_item_new_with_mnemonic(_("Power _Down"));
+ gtk_menu_append(GTK_MENU(s->machine_menu), s->powerdown_item);
+
+ separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(s->machine_menu), separator);
+
+ s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
+ gtk_stock_lookup(GTK_STOCK_QUIT, &item);
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
+ "<QEMU>/Machine/Quit");
+ gtk_accel_map_add_entry("<QEMU>/Machine/Quit", item.keyval, item.modifier);
+ gtk_menu_append(GTK_MENU(s->machine_menu), s->quit_item);
+
+ s->view_menu = gtk_menu_new();
+ gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
+ s->view_menu_item = gtk_menu_item_new_with_mnemonic(_("_View"));
+
+ s->full_screen_item =
+ gtk_image_menu_item_new_from_stock(GTK_STOCK_FULLSCREEN, NULL);
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item),
+ "<QEMU>/View/Full Screen");
+ gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_menu_append(GTK_MENU(s->view_menu), s->full_screen_item);
+
+ separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+ s->zoom_in_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_IN, NULL);
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item),
+ "<QEMU>/View/Zoom In");
+ gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_in_item);
+
+ s->zoom_out_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_OUT, NULL);
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item),
+ "<QEMU>/View/Zoom Out");
+ gtk_accel_map_add_entry("<QEMU>/View/Zoom Out", GDK_KEY_minus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_out_item);
+
+ s->zoom_fixed_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_100, NULL);
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item),
+ "<QEMU>/View/Zoom Fixed");
+ gtk_accel_map_add_entry("<QEMU>/View/Zoom Fixed", GDK_KEY_0, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fixed_item);
+
+ s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic(_("Zoom To _Fit"));
+ gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fit_item);
+
+ separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+ s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic(_("Grab On _Hover"));
+ gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item);
+
+ s->grab_item = gtk_check_menu_item_new_with_mnemonic(_("_Grab Input"));
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item),
+ "<QEMU>/View/Grab Input");
+ gtk_accel_map_add_entry("<QEMU>/View/Grab Input", GDK_KEY_g, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_menu_append(GTK_MENU(s->view_menu), s->grab_item);
+
+ separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+ s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
+ group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
+ "<QEMU>/View/VGA");
+ gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
+
+ for (i = 0; i < nb_vcs; i++) {
+ VirtualConsole *vc = &s->vc[i];
+
+ group = gd_vc_init(s, vc, i, group);
+ s->nb_vcs++;
+ }
+
+ separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+ s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic(_("Show _Tabs"));
+ gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
+
+ g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
+ gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
+ s->accel_group = accel_group;
+
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item),
+ s->machine_menu);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->machine_menu_item);
+
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item);
+}
+
+void gtk_display_init(DisplayState *ds)
+{
+ GtkDisplayState *s = g_malloc0(sizeof(*s));
+
+ gtk_init(NULL, NULL);
+
+ ds->opaque = s;
+ s->ds = ds;
+ s->dcl.dpy_gfx_update = gd_update;
+ s->dcl.dpy_gfx_resize = gd_resize;
+ s->dcl.dpy_refresh = gd_refresh;
+
+ s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ s->vbox = gtk_vbox_new(FALSE, 0);
+ s->notebook = gtk_notebook_new();
+ s->drawing_area = gtk_drawing_area_new();
+ s->menu_bar = gtk_menu_bar_new();
+
+ s->scale_x = 1.0;
+ s->scale_y = 1.0;
+ s->free_scale = FALSE;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR);
+ textdomain("qemu");
+
+ s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
+
+ s->mouse_mode_notifier.notify = gd_mouse_mode_change;
+ qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
+ qemu_add_vm_change_state_handler(gd_change_runstate, s);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
+
+ gd_create_menus(s);
+
+ gd_connect_signals(s);
+
+ gtk_widget_add_events(s->drawing_area,
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_SCROLL_MASK |
+ GDK_KEY_PRESS_MASK);
+ gtk_widget_set_double_buffered(s->drawing_area, FALSE);
+ gtk_widget_set_can_focus(s->drawing_area, TRUE);
+
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
+ gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
+
+ gd_update_caption(s);
+
+ gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0);
+
+ gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
+
+ gtk_widget_show_all(s->window);
+
+ register_displaychangelistener(ds, &s->dcl);
+
+ global_state = s;
+}
diff --git a/user-exec.c b/user-exec.c
index c71acbc503..71bd6c531c 100644
--- a/user-exec.c
+++ b/user-exec.c
@@ -70,7 +70,7 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc)
#endif
}
env1->exception_index = -1;
- longjmp(env1->jmp_env, 1);
+ siglongjmp(env1->jmp_env, 1);
}
/* 'pc' is the host PC at which the exception was raised. 'address' is
diff --git a/vl.c b/vl.c
index 955d2ffe0f..0da156e8b4 100644
--- a/vl.c
+++ b/vl.c
@@ -2207,6 +2207,13 @@ static DisplayType select_display(const char *p)
fprintf(stderr, "Curses support is disabled\n");
exit(1);
#endif
+ } else if (strstart(p, "gtk", &opts)) {
+#ifdef CONFIG_GTK
+ display = DT_GTK;
+#else
+ fprintf(stderr, "GTK support is disabled\n");
+ exit(1);
+#endif
} else if (strstart(p, "none", &opts)) {
display = DT_NONE;
} else {
@@ -3999,6 +4006,28 @@ int main(int argc, char **argv, char **envp)
}
}
+ if (using_spice) {
+ display_remote++;
+ }
+ if (display_type == DT_DEFAULT && !display_remote) {
+#if defined(CONFIG_GTK)
+ display_type = DT_GTK;
+#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA)
+ display_type = DT_SDL;
+#elif defined(CONFIG_VNC)
+ vnc_display = "localhost:0,to=99";
+ show_vnc_port = 1;
+#else
+ display_type = DT_NONE;
+#endif
+ }
+
+#if defined(CONFIG_GTK)
+ if (display_type == DT_GTK) {
+ early_gtk_display_init();
+ }
+#endif
+
socket_init();
if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0)
@@ -4227,20 +4256,6 @@ int main(int argc, char **argv, char **envp)
/* just use the first displaystate for the moment */
ds = get_displaystate();
- if (using_spice)
- display_remote++;
- if (display_type == DT_DEFAULT && !display_remote) {
-#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
- display_type = DT_SDL;
-#elif defined(CONFIG_VNC)
- vnc_display = "localhost:0,to=99";
- show_vnc_port = 1;
-#else
- display_type = DT_NONE;
-#endif
- }
-
-
/* init local displays */
switch (display_type) {
case DT_NOGRAPHIC:
@@ -4259,6 +4274,11 @@ int main(int argc, char **argv, char **envp)
cocoa_display_init(ds, full_screen);
break;
#endif
+#if defined(CONFIG_GTK)
+ case DT_GTK:
+ gtk_display_init(ds);
+ break;
+#endif
default:
break;
}