[Spice-commits] 39 commits - configure default-configs/usb.mak hw/i2c hw/ide hw/usb include/qemu net/net.c qemu-doc.texi qemu-options.hx qga/commands-posix.c qga/qapi-schema.json scripts/coverity-model.c tcg/README tcg/aarch64 tcg/arm tcg/i386 tcg/ia64 tcg/mips tcg/optimize.c tcg/ppc tcg/ppc64 tcg/s390 tcg/sparc tcg/tcg-be-ldst.h tcg/tcg-op.h tcg/tcg.c tcg/tcg.h tcg/tci tci.c trace-events vl.c xbzrle.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Fri Apr 25 02:13:12 PDT 2014


 configure                |    5 
 default-configs/usb.mak  |    1 
 hw/i2c/smbus_eeprom.c    |    2 
 hw/ide/ahci.c            |    4 
 hw/usb/Makefile.objs     |    4 
 hw/usb/desc-msos.c       |    6 
 hw/usb/desc.h            |    1 
 hw/usb/dev-mtp.c         | 1103 +++++++++++++++++++++++++++++++++++++++++++++++
 include/qemu/int128.h    |    4 
 net/net.c                |    4 
 qemu-doc.texi            |    2 
 qemu-options.hx          |    7 
 qga/commands-posix.c     |    2 
 qga/qapi-schema.json     |   14 
 scripts/coverity-model.c |  183 +++++++
 tcg/README               |   18 
 tcg/aarch64/tcg-target.c |   48 --
 tcg/aarch64/tcg-target.h |    1 
 tcg/arm/tcg-target.c     |    8 
 tcg/arm/tcg-target.h     |    2 
 tcg/i386/tcg-target.c    |    8 
 tcg/i386/tcg-target.h    |    2 
 tcg/ia64/tcg-target.c    |  500 +++++++++++----------
 tcg/ia64/tcg-target.h    |    2 
 tcg/mips/tcg-target.c    |   14 
 tcg/mips/tcg-target.h    |    5 
 tcg/optimize.c           |   45 +
 tcg/ppc/tcg-target.c     |    8 
 tcg/ppc/tcg-target.h     |    2 
 tcg/ppc64/tcg-target.c   |   12 
 tcg/ppc64/tcg-target.h   |    1 
 tcg/s390/tcg-target.c    |   45 -
 tcg/s390/tcg-target.h    |    2 
 tcg/sparc/tcg-target.c   |   10 
 tcg/sparc/tcg-target.h   |    2 
 tcg/tcg-be-ldst.h        |    2 
 tcg/tcg-op.h             |   48 --
 tcg/tcg.c                |   14 
 tcg/tcg.h                |    8 
 tcg/tci/tcg-target.c     |    2 
 tcg/tci/tcg-target.h     |    8 
 tci.c                    |   20 
 trace-events             |   21 
 vl.c                     |    2 
 xbzrle.c                 |    8 
 45 files changed, 1782 insertions(+), 428 deletions(-)

New commits:
commit 0e96643c98eb22a5f2e11ac500852133032d38e4
Merge: ad600a4 840a178
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Apr 24 16:16:57 2014 +0100

    Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-5' into staging
    
    usb: mtp filesharing
    
    # gpg: Signature made Wed 23 Apr 2014 09:28:37 BST using RSA key ID D3E87138
    # gpg: Good signature from "Gerd Hoffmann (work) <kraxel at redhat.com>"
    # gpg:                 aka "Gerd Hoffmann <gerd at kraxel.org>"
    # gpg:                 aka "Gerd Hoffmann (private) <kraxel at gmail.com>"
    
    * remotes/kraxel/tags/pull-usb-5:
      usb: mtp filesharing
      usb: add CompatibleID support to msos
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

commit ad600a4d49293f6b8eda7932f90e5aa5fa2021b0
Merge: ba3627e 02eb19d
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Apr 24 15:24:51 2014 +0100

    Merge remote-tracking branch 'remotes/rth/tags/tcg-next-20140422' into staging
    
    Pull tcg 2014-04-22
    
    # gpg: Signature made Tue 22 Apr 2014 22:00:04 BST using RSA key ID 4DD0279B
    # gpg: Can't check signature: public key not found
    
    * remotes/rth/tags/tcg-next-20140422:
      tcg: Use HOST_WORDS_BIGENDIAN
      tcg: Fix fallback from muls2_i64 to mulu2_i64
      tcg: Use tcg_gen_mulu2_i32 in tcg_gen_muls2_i32
      tcg: Relax requirement for mulu2_i32 on 32-bit hosts
      tcg-s390: Remove W constraint
      tcg-sparc: Use the type parameter to tcg_target_const_match
      tcg-ppc64: Use the type parameter to tcg_target_const_match
      tcg-aarch64: Remove w constraint
      tcg: Add TCGType parameter to tcg_target_const_match
      tcg: Fix out of range shift in deposit optimizations
      tci: Mask shift counts to avoid undefined behavior
      tcg: Mask shift quantities while folding
      tcg: Use "unspecified behavior" for shifts
      tcg: Fix warning (1 bit signed bitfield entry) and replace int by bool
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

commit ba3627ec384d6c68e87c466895a4d78422669e30
Merge: 4b8abfb 0374f50
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Apr 24 14:14:51 2014 +0100

    Merge remote-tracking branch 'remotes/rth/tags/tcg-ia64-pull-20140421' into staging
    
    Pull for 20140421
    
    # gpg: Signature made Mon 21 Apr 2014 17:57:24 BST using RSA key ID 4DD0279B
    # gpg: Can't check signature: public key not found
    
    * remotes/rth/tags/tcg-ia64-pull-20140421:
      tcg-ia64: Convert to new ldst opcodes
      tcg-ia64: Move part of softmmu slow path out of line
      tcg-ia64: Convert to new ldst helpers
      tcg-ia64: Reduce code duplication in tcg_out_qemu_ld
      tcg-ia64: Move tlb addend load into tlb read
      tcg-ia64: Move bswap for store into tlb load
      tcg-ia64: Re-bundle the tlb load
      tcg-ia64: Optimize small arguments to exit_tb
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

commit 4b8abfb78e99c1fef23a5bd99ea9ab4718dfb57d
Merge: 2d03b49 b36dc67
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Apr 24 13:22:16 2014 +0100

    Merge remote-tracking branch 'remotes/mjt/tags/trivial-patches-2014-04-18' into staging
    
    trivial patches for 2014-04-18
    
    # gpg: Signature made Fri 18 Apr 2014 07:36:15 BST using RSA key ID A4C3D7DB
    # gpg: Good signature from "Michael Tokarev <mjt at tls.msk.ru>"
    # gpg:                 aka "Michael Tokarev <mjt at corpit.ru>"
    # gpg:                 aka "Michael Tokarev <mjt at debian.org>"
    # gpg: WARNING: This key is not certified with a trusted signature!
    # gpg:          There is no indication that the signature belongs to the owner.
    # Primary key fingerprint: 6EE1 95D1 886E 8FFB 810D  4324 457C E0A0 8044 65C5
    #      Subkey fingerprint: 6F67 E18E 7C91 C5B1 5514  66A7 BEE5 9D74 A4C3 D7DB
    
    * remotes/mjt/tags/trivial-patches-2014-04-18:
      Fix grammar in comment
      doc: grammify "allows to"
      configure: Remove redundant message for -Werror
      scripts: add sample model file for Coverity Scan
      xbzrle.c: Avoid undefined behaviour with signed arithmetic
      int128.h: Avoid undefined behaviours involving signed arithmetic
      hw/ide/ahci.c: Avoid shift left into sign bit
      net: Report error when device / hub combo is not found.
      configure: Fix indentation of help for --enable/disable-debug-info
      qga: trivial fix for unclear documentation of guest-set-time
      vl: Report accelerator not supported for target more nicely
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

commit 840a178c94dbd3f5b5550fb8621620cb761de72d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Oct 18 10:26:09 2012 +0200

    usb: mtp filesharing
    
    Implementation of a USB Media Transfer Device device for easy
    filesharing.  Read-only.  No access control inside qemu, it will
    happily export any file it is able to open to the guest, i.e.
    standard unix access rights for the qemu process apply.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/default-configs/usb.mak b/default-configs/usb.mak
index 1bf9075..73d8489 100644
--- a/default-configs/usb.mak
+++ b/default-configs/usb.mak
@@ -1,6 +1,7 @@
 CONFIG_USB_TABLET_WACOM=y
 CONFIG_USB_STORAGE_BOT=y
 CONFIG_USB_STORAGE_UAS=y
+CONFIG_USB_STORAGE_MTP=y
 CONFIG_USB_SMARTCARD=y
 CONFIG_USB_AUDIO=y
 CONFIG_USB_SERIAL=y
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 97b4575..17d460c 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -26,6 +26,10 @@ common-obj-y                          += ccid-card-passthru.o
 common-obj-$(CONFIG_SMARTCARD_NSS)    += ccid-card-emulated.o
 endif
 
+ifeq ($(CONFIG_POSIX),y)
+common-obj-$(CONFIG_USB_STORAGE_MTP)  += dev-mtp.o
+endif
+
 # usb redirection
 common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
 
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
new file mode 100644
index 0000000..8b44032
--- /dev/null
+++ b/hw/usb/dev-mtp.c
@@ -0,0 +1,1103 @@
+/*
+ * Media Transfer Protocol implementation, backed by host filesystem.
+ *
+ * Copyright Red Hat, Inc 2014
+ *
+ * Author:
+ *   Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This code is licensed under the GPL v2 or later.
+ */
+
+#include <wchar.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+
+#include "qemu-common.h"
+#include "qemu/iov.h"
+#include "trace.h"
+#include "hw/usb.h"
+#include "hw/usb/desc.h"
+
+/* ----------------------------------------------------------------------- */
+
+enum mtp_container_type {
+    TYPE_COMMAND  = 1,
+    TYPE_DATA     = 2,
+    TYPE_RESPONSE = 3,
+    TYPE_EVENT    = 4,
+};
+
+enum mtp_code {
+    /* command codes */
+    CMD_GET_DEVICE_INFO            = 0x1001,
+    CMD_OPEN_SESSION               = 0x1002,
+    CMD_CLOSE_SESSION              = 0x1003,
+    CMD_GET_STORAGE_IDS            = 0x1004,
+    CMD_GET_STORAGE_INFO           = 0x1005,
+    CMD_GET_NUM_OBJECTS            = 0x1006,
+    CMD_GET_OBJECT_HANDLES         = 0x1007,
+    CMD_GET_OBJECT_INFO            = 0x1008,
+    CMD_GET_OBJECT                 = 0x1009,
+    CMD_GET_PARTIAL_OBJECT         = 0x101b,
+
+    /* response codes */
+    RES_OK                         = 0x2001,
+    RES_SESSION_NOT_OPEN           = 0x2003,
+    RES_INVALID_TRANSACTION_ID     = 0x2004,
+    RES_OPERATION_NOT_SUPPORTED    = 0x2005,
+    RES_PARAMETER_NOT_SUPPORTED    = 0x2006,
+    RES_INVALID_STORAGE_ID         = 0x2008,
+    RES_INVALID_OBJECT_HANDLE      = 0x2009,
+    RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
+    RES_INVALID_PARENT_OBJECT      = 0x201a,
+    RES_INVALID_PARAMETER          = 0x201d,
+    RES_SESSION_ALREADY_OPEN       = 0x201e,
+
+    /* format codes */
+    FMT_UNDEFINED_OBJECT           = 0x3000,
+    FMT_ASSOCIATION                = 0x3001,
+};
+
+typedef struct {
+    uint32_t length;
+    uint16_t type;
+    uint16_t code;
+    uint32_t trans;
+} QEMU_PACKED mtp_container;
+
+/* ----------------------------------------------------------------------- */
+
+typedef struct MTPState MTPState;
+typedef struct MTPControl MTPControl;
+typedef struct MTPData MTPData;
+typedef struct MTPObject MTPObject;
+
+enum {
+    EP_DATA_IN = 1,
+    EP_DATA_OUT,
+    EP_EVENT,
+};
+
+struct MTPControl {
+    uint16_t     code;
+    uint32_t     trans;
+    int          argc;
+    uint32_t     argv[5];
+};
+
+struct MTPData {
+    uint16_t     code;
+    uint32_t     trans;
+    uint32_t     offset;
+    uint32_t     length;
+    uint32_t     alloc;
+    uint8_t      *data;
+    bool         first;
+    int          fd;
+};
+
+struct MTPObject {
+    uint32_t     handle;
+    uint16_t     format;
+    char         *name;
+    char         *path;
+    struct stat  stat;
+    MTPObject    *parent;
+    MTPObject    **children;
+    int32_t      nchildren;
+    QTAILQ_ENTRY(MTPObject) next;
+};
+
+struct MTPState {
+    USBDevice    dev;
+    char         *root;
+    char         *desc;
+    uint32_t     flags;
+
+    MTPData      *data_in;
+    MTPData      *data_out;
+    MTPControl   *result;
+    uint32_t     session;
+    uint32_t     next_handle;
+
+    QTAILQ_HEAD(, MTPObject) objects;
+};
+
+#define QEMU_STORAGE_ID 0x00010001
+
+#define MTP_FLAG_WRITABLE 0
+
+#define FLAG_SET(_mtp, _flag)  ((_mtp)->flags & (1 << (_flag)))
+
+/* ----------------------------------------------------------------------- */
+
+#define MTP_MANUFACTURER  "QEMU"
+#define MTP_PRODUCT       "QEMU filesharing"
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+    STR_CONFIG_FULL,
+    STR_CONFIG_HIGH,
+    STR_CONFIG_SUPER,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER] = MTP_MANUFACTURER,
+    [STR_PRODUCT]      = MTP_PRODUCT,
+    [STR_SERIALNUMBER] = "34617",
+    [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
+    [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
+    [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
+};
+
+static const USBDescIface desc_iface_full = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 3,
+    .bInterfaceClass               = USB_CLASS_STILL_IMAGE,
+    .bInterfaceSubClass            = 0x01,
+    .bInterfaceProtocol            = 0x01,
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | EP_DATA_IN,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | EP_DATA_OUT,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | EP_EVENT,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 8,
+            .bInterval             = 0x0a,
+        },
+    }
+};
+
+static const USBDescDevice desc_device_full = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_FULL,
+            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
+            .bMaxPower             = 2,
+            .nif = 1,
+            .ifs = &desc_iface_full,
+        },
+    },
+};
+
+static const USBDescIface desc_iface_high = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 3,
+    .bInterfaceClass               = USB_CLASS_STILL_IMAGE,
+    .bInterfaceSubClass            = 0x01,
+    .bInterfaceProtocol            = 0x01,
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | EP_DATA_IN,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 512,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | EP_DATA_OUT,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 512,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | EP_EVENT,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 8,
+            .bInterval             = 0x0a,
+        },
+    }
+};
+
+static const USBDescDevice desc_device_high = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_HIGH,
+            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
+            .bMaxPower             = 2,
+            .nif = 1,
+            .ifs = &desc_iface_high,
+        },
+    },
+};
+
+static const USBDescMSOS desc_msos = {
+    .CompatibleID = "MTP",
+    .SelectiveSuspendEnabled = true,
+};
+
+static const USBDesc desc = {
+    .id = {
+        .idVendor          = 0x46f4, /* CRC16() of "QEMU" */
+        .idProduct         = 0x0004,
+        .bcdDevice         = 0,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full  = &desc_device_full,
+    .high  = &desc_device_high,
+    .str   = desc_strings,
+    .msos  = &desc_msos,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
+                                       MTPObject *parent, char *name)
+{
+    MTPObject *o = g_new0(MTPObject, 1);
+
+    if (name[0] == '.') {
+        goto ignore;
+    }
+
+    o->handle = handle;
+    o->parent = parent;
+    o->name = g_strdup(name);
+    o->nchildren = -1;
+    if (parent == NULL) {
+        o->path = g_strdup(name);
+    } else {
+        o->path = g_strdup_printf("%s/%s", parent->path, name);
+    }
+
+    if (lstat(o->path, &o->stat) != 0) {
+        goto ignore;
+    }
+    if (S_ISREG(o->stat.st_mode)) {
+        o->format = FMT_UNDEFINED_OBJECT;
+    } else if (S_ISDIR(o->stat.st_mode)) {
+        o->format = FMT_ASSOCIATION;
+    } else {
+        goto ignore;
+    }
+
+    if (access(o->path, R_OK) != 0) {
+        goto ignore;
+    }
+
+    fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+
+    QTAILQ_INSERT_TAIL(&s->objects, o, next);
+    return o;
+
+ignore:
+    g_free(o->name);
+    g_free(o->path);
+    g_free(o);
+    return NULL;
+}
+
+static void usb_mtp_object_free(MTPState *s, MTPObject *o)
+{
+    int i;
+
+    fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+
+    QTAILQ_REMOVE(&s->objects, o, next);
+    for (i = 0; i < o->nchildren; i++) {
+        usb_mtp_object_free(s, o->children[i]);
+    }
+    g_free(o->children);
+    g_free(o->name);
+    g_free(o->path);
+    g_free(o);
+}
+
+static MTPObject *usb_mtp_object_lookup(MTPState *s, uint32_t handle)
+{
+    MTPObject *o;
+
+    QTAILQ_FOREACH(o, &s->objects, next) {
+        if (o->handle == handle) {
+            return o;
+        }
+    }
+    return NULL;
+}
+
+static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
+{
+    struct dirent *entry;
+    DIR *dir;
+
+    o->nchildren = 0;
+    dir = opendir(o->path);
+    if (!dir) {
+        return;
+    }
+    while ((entry = readdir(dir)) != NULL) {
+        if ((o->nchildren % 32) == 0) {
+            o->children = g_realloc(o->children,
+                                    (o->nchildren + 32) * sizeof(MTPObject *));
+        }
+        o->children[o->nchildren] =
+            usb_mtp_object_alloc(s, s->next_handle++, o, entry->d_name);
+        if (o->children[o->nchildren] != NULL) {
+            o->nchildren++;
+        }
+    }
+    closedir(dir);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static MTPData *usb_mtp_data_alloc(MTPControl *c)
+{
+    MTPData *data = g_new0(MTPData, 1);
+
+    data->code  = c->code;
+    data->trans = c->trans;
+    data->fd    = -1;
+    data->first = true;
+    return data;
+}
+
+static void usb_mtp_data_free(MTPData *data)
+{
+    if (data == NULL) {
+        return;
+    }
+    if (data->fd != -1) {
+        close(data->fd);
+    }
+    g_free(data->data);
+    g_free(data);
+}
+
+static void usb_mtp_realloc(MTPData *data, uint32_t bytes)
+{
+    if (data->length + bytes <= data->alloc) {
+        return;
+    }
+    data->alloc = (data->length + bytes + 0xff) & ~0xff;
+    data->data  = g_realloc(data->data, data->alloc);
+}
+
+static void usb_mtp_add_u8(MTPData *data, uint8_t val)
+{
+    usb_mtp_realloc(data, 1);
+    data->data[data->length++] = val;
+}
+
+static void usb_mtp_add_u16(MTPData *data, uint16_t val)
+{
+    usb_mtp_realloc(data, 2);
+    data->data[data->length++] = (val >> 0) & 0xff;
+    data->data[data->length++] = (val >> 8) & 0xff;
+}
+
+static void usb_mtp_add_u32(MTPData *data, uint32_t val)
+{
+    usb_mtp_realloc(data, 4);
+    data->data[data->length++] = (val >>  0) & 0xff;
+    data->data[data->length++] = (val >>  8) & 0xff;
+    data->data[data->length++] = (val >> 16) & 0xff;
+    data->data[data->length++] = (val >> 24) & 0xff;
+}
+
+static void usb_mtp_add_u64(MTPData *data, uint64_t val)
+{
+    usb_mtp_realloc(data, 4);
+    data->data[data->length++] = (val >>  0) & 0xff;
+    data->data[data->length++] = (val >>  8) & 0xff;
+    data->data[data->length++] = (val >> 16) & 0xff;
+    data->data[data->length++] = (val >> 24) & 0xff;
+    data->data[data->length++] = (val >> 32) & 0xff;
+    data->data[data->length++] = (val >> 40) & 0xff;
+    data->data[data->length++] = (val >> 48) & 0xff;
+    data->data[data->length++] = (val >> 54) & 0xff;
+}
+
+static void usb_mtp_add_u16_array(MTPData *data, uint32_t len,
+                                  const uint16_t *vals)
+{
+    int i;
+
+    usb_mtp_add_u32(data, len);
+    for (i = 0; i < len; i++) {
+        usb_mtp_add_u16(data, vals[i]);
+    }
+}
+
+static void usb_mtp_add_u32_array(MTPData *data, uint32_t len,
+                                  const uint32_t *vals)
+{
+    int i;
+
+    usb_mtp_add_u32(data, len);
+    for (i = 0; i < len; i++) {
+        usb_mtp_add_u32(data, vals[i]);
+    }
+}
+
+static void usb_mtp_add_wstr(MTPData *data, const wchar_t *str)
+{
+    uint32_t len = wcslen(str);
+    int i;
+
+    if (len > 0) {
+        len++; /* include terminating L'\0' */
+    }
+
+    usb_mtp_add_u8(data, len);
+    for (i = 0; i < len; i++) {
+        usb_mtp_add_u16(data, str[i]);
+    }
+}
+
+static void usb_mtp_add_str(MTPData *data, const char *str)
+{
+    uint32_t len = strlen(str)+1;
+    wchar_t wstr[len];
+    size_t ret;
+
+    ret = mbstowcs(wstr, str, len);
+    if (ret == -1) {
+        usb_mtp_add_wstr(data, L"Oops");
+    } else {
+        usb_mtp_add_wstr(data, wstr);
+    }
+}
+
+static void usb_mtp_add_time(MTPData *data, time_t time)
+{
+    char buf[16];
+    struct tm tm;
+
+    gmtime_r(&time, &tm);
+    strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm);
+    usb_mtp_add_str(data, buf);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void usb_mtp_queue_result(MTPState *s, uint16_t code, uint32_t trans,
+                                 int argc, uint32_t arg0, uint32_t arg1)
+{
+    MTPControl *c = g_new0(MTPControl, 1);
+
+    c->code  = code;
+    c->trans = trans;
+    c->argc  = argc;
+    if (argc > 0) {
+        c->argv[0] = arg0;
+    }
+    if (argc > 1) {
+        c->argv[1] = arg1;
+    }
+
+    assert(s->result == NULL);
+    s->result = c;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
+{
+    static const uint16_t ops[] = {
+        CMD_GET_DEVICE_INFO,
+        CMD_OPEN_SESSION,
+        CMD_CLOSE_SESSION,
+        CMD_GET_STORAGE_IDS,
+        CMD_GET_STORAGE_INFO,
+        CMD_GET_NUM_OBJECTS,
+        CMD_GET_OBJECT_HANDLES,
+        CMD_GET_OBJECT_INFO,
+        CMD_GET_OBJECT,
+        CMD_GET_PARTIAL_OBJECT,
+    };
+    static const uint16_t fmt[] = {
+        FMT_UNDEFINED_OBJECT,
+        FMT_ASSOCIATION,
+    };
+    MTPData *d = usb_mtp_data_alloc(c);
+
+    trace_usb_mtp_op_get_device_info(s->dev.addr);
+
+    usb_mtp_add_u16(d, 0x0100);
+    usb_mtp_add_u32(d, 0xffffffff);
+    usb_mtp_add_u16(d, 0x0101);
+    usb_mtp_add_wstr(d, L"");
+    usb_mtp_add_u16(d, 0x0000);
+
+    usb_mtp_add_u16_array(d, ARRAY_SIZE(ops), ops);
+    usb_mtp_add_u16_array(d, 0, NULL);
+    usb_mtp_add_u16_array(d, 0, NULL);
+    usb_mtp_add_u16_array(d, 0, NULL);
+    usb_mtp_add_u16_array(d, ARRAY_SIZE(fmt), fmt);
+
+    usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER);
+    usb_mtp_add_wstr(d, L"" MTP_PRODUCT);
+    usb_mtp_add_wstr(d, L"0.1");
+    usb_mtp_add_wstr(d, L"123456789abcdef123456789abcdef");
+
+    return d;
+}
+
+static MTPData *usb_mtp_get_storage_ids(MTPState *s, MTPControl *c)
+{
+    static const uint32_t ids[] = {
+        QEMU_STORAGE_ID,
+    };
+    MTPData *d = usb_mtp_data_alloc(c);
+
+    trace_usb_mtp_op_get_storage_ids(s->dev.addr);
+
+    usb_mtp_add_u32_array(d, ARRAY_SIZE(ids), ids);
+
+    return d;
+}
+
+static MTPData *usb_mtp_get_storage_info(MTPState *s, MTPControl *c)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+    struct statvfs buf;
+    int rc;
+
+    trace_usb_mtp_op_get_storage_info(s->dev.addr);
+
+    if (FLAG_SET(s, MTP_FLAG_WRITABLE)) {
+        usb_mtp_add_u16(d, 0x0003);
+        usb_mtp_add_u16(d, 0x0002);
+        usb_mtp_add_u16(d, 0x0000);
+    } else {
+        usb_mtp_add_u16(d, 0x0001);
+        usb_mtp_add_u16(d, 0x0002);
+        usb_mtp_add_u16(d, 0x0001);
+    }
+
+    rc = statvfs(s->root, &buf);
+    if (rc == 0) {
+        usb_mtp_add_u64(d, (uint64_t)buf.f_frsize * buf.f_blocks);
+        usb_mtp_add_u64(d, (uint64_t)buf.f_bavail * buf.f_blocks);
+        usb_mtp_add_u32(d, buf.f_ffree);
+    } else {
+        usb_mtp_add_u64(d, 0xffffffff);
+        usb_mtp_add_u64(d, 0xffffffff);
+        usb_mtp_add_u32(d, 0xffffffff);
+    }
+
+    usb_mtp_add_str(d, s->desc);
+    usb_mtp_add_wstr(d, L"123456789abcdef");
+    return d;
+}
+
+static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c,
+                                           MTPObject *o)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+    uint32_t i, handles[o->nchildren];
+
+    trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path);
+
+    for (i = 0; i < o->nchildren; i++) {
+        handles[i] = o->children[i]->handle;
+    }
+    usb_mtp_add_u32_array(d, o->nchildren, handles);
+
+    return d;
+}
+
+static MTPData *usb_mtp_get_object_info(MTPState *s, MTPControl *c,
+                                        MTPObject *o)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+
+    trace_usb_mtp_op_get_object_info(s->dev.addr, o->handle, o->path);
+
+    usb_mtp_add_u32(d, QEMU_STORAGE_ID);
+    usb_mtp_add_u16(d, o->format);
+    usb_mtp_add_u16(d, 0);
+    usb_mtp_add_u32(d, o->stat.st_size);
+
+    usb_mtp_add_u16(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+    usb_mtp_add_u32(d, 0);
+
+    if (o->parent) {
+        usb_mtp_add_u32(d, o->parent->handle);
+    } else {
+        usb_mtp_add_u32(d, 0);
+    }
+    if (o->format == FMT_ASSOCIATION) {
+        usb_mtp_add_u16(d, 0x0001);
+        usb_mtp_add_u32(d, 0x00000001);
+        usb_mtp_add_u32(d, 0);
+    } else {
+        usb_mtp_add_u16(d, 0);
+        usb_mtp_add_u32(d, 0);
+        usb_mtp_add_u32(d, 0);
+    }
+
+    usb_mtp_add_str(d, o->name);
+    usb_mtp_add_time(d, o->stat.st_ctime);
+    usb_mtp_add_time(d, o->stat.st_mtime);
+    usb_mtp_add_wstr(d, L"");
+
+    return d;
+}
+
+static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c,
+                                   MTPObject *o)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+
+    trace_usb_mtp_op_get_object(s->dev.addr, o->handle, o->path);
+
+    d->fd = open(o->path, O_RDONLY);
+    if (d->fd == -1) {
+        return NULL;
+    }
+    d->length = o->stat.st_size;
+    d->alloc  = 512;
+    d->data   = g_malloc(d->alloc);
+    return d;
+}
+
+static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
+                                           MTPObject *o)
+{
+    MTPData *d = usb_mtp_data_alloc(c);
+    off_t offset;
+
+    trace_usb_mtp_op_get_partial_object(s->dev.addr, o->handle, o->path,
+                                        c->argv[1], c->argv[2]);
+
+    d->fd = open(o->path, O_RDONLY);
+    if (d->fd == -1) {
+        return NULL;
+    }
+
+    offset = c->argv[1];
+    if (offset > o->stat.st_size) {
+        offset = o->stat.st_size;
+    }
+    lseek(d->fd, offset, SEEK_SET);
+
+    d->length = c->argv[2];
+    if (d->length > o->stat.st_size - offset) {
+        d->length = o->stat.st_size - offset;
+    }
+
+    return d;
+}
+
+static void usb_mtp_command(MTPState *s, MTPControl *c)
+{
+    MTPData *data_in = NULL;
+    MTPObject *o;
+    uint32_t nres = 0, res0 = 0;
+
+    /* sanity checks */
+    if (c->code >= CMD_CLOSE_SESSION && s->session == 0) {
+        usb_mtp_queue_result(s, RES_SESSION_NOT_OPEN,
+                             c->trans, 0, 0, 0);
+        return;
+    }
+
+    /* process commands */
+    switch (c->code) {
+    case CMD_GET_DEVICE_INFO:
+        data_in = usb_mtp_get_device_info(s, c);
+        break;
+    case CMD_OPEN_SESSION:
+        if (s->session) {
+            usb_mtp_queue_result(s, RES_SESSION_ALREADY_OPEN,
+                                 c->trans, 1, s->session, 0);
+            return;
+        }
+        if (c->argv[0] == 0) {
+            usb_mtp_queue_result(s, RES_INVALID_PARAMETER,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        trace_usb_mtp_op_open_session(s->dev.addr);
+        s->session = c->argv[0];
+        usb_mtp_object_alloc(s, s->next_handle++, NULL, s->root);
+        break;
+    case CMD_CLOSE_SESSION:
+        trace_usb_mtp_op_close_session(s->dev.addr);
+        s->session = 0;
+        s->next_handle = 0;
+        usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
+        assert(QTAILQ_EMPTY(&s->objects));
+        break;
+    case CMD_GET_STORAGE_IDS:
+        data_in = usb_mtp_get_storage_ids(s, c);
+        break;
+    case CMD_GET_STORAGE_INFO:
+        if (c->argv[0] != QEMU_STORAGE_ID &&
+            c->argv[0] != 0xffffffff) {
+            usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        data_in = usb_mtp_get_storage_info(s, c);
+        break;
+    case CMD_GET_NUM_OBJECTS:
+    case CMD_GET_OBJECT_HANDLES:
+        if (c->argv[0] != QEMU_STORAGE_ID &&
+            c->argv[0] != 0xffffffff) {
+            usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (c->argv[1] != 0x00000000) {
+            usb_mtp_queue_result(s, RES_SPEC_BY_FORMAT_UNSUPPORTED,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (c->argv[2] == 0x00000000 ||
+            c->argv[2] == 0xffffffff) {
+            o = QTAILQ_FIRST(&s->objects);
+        } else {
+            o = usb_mtp_object_lookup(s, c->argv[2]);
+        }
+        if (o == NULL) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (o->format != FMT_ASSOCIATION) {
+            usb_mtp_queue_result(s, RES_INVALID_PARENT_OBJECT,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (o->nchildren == -1) {
+            usb_mtp_object_readdir(s, o);
+        }
+        if (c->code == CMD_GET_NUM_OBJECTS) {
+            trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
+            nres = 1;
+            res0 = o->nchildren;
+        } else {
+            data_in = usb_mtp_get_object_handles(s, c, o);
+        }
+        break;
+    case CMD_GET_OBJECT_INFO:
+        o = usb_mtp_object_lookup(s, c->argv[0]);
+        if (o == NULL) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        data_in = usb_mtp_get_object_info(s, c, o);
+        break;
+    case CMD_GET_OBJECT:
+        o = usb_mtp_object_lookup(s, c->argv[0]);
+        if (o == NULL) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (o->format == FMT_ASSOCIATION) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        data_in = usb_mtp_get_object(s, c, o);
+        if (NULL == data_in) {
+            fprintf(stderr, "%s: TODO: handle error\n", __func__);
+        }
+        break;
+    case CMD_GET_PARTIAL_OBJECT:
+        o = usb_mtp_object_lookup(s, c->argv[0]);
+        if (o == NULL) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        if (o->format == FMT_ASSOCIATION) {
+            usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
+                                 c->trans, 0, 0, 0);
+            return;
+        }
+        data_in = usb_mtp_get_partial_object(s, c, o);
+        if (NULL == data_in) {
+            fprintf(stderr, "%s: TODO: handle error\n", __func__);
+        }
+        nres = 1;
+        res0 = data_in->length;
+        break;
+    default:
+        fprintf(stderr, "%s: unknown command code 0x%04x\n",
+                __func__, c->code);
+        usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
+                             c->trans, 0, 0, 0);
+        return;
+    }
+
+    /* return results on success */
+    if (data_in) {
+        assert(s->data_in == NULL);
+        s->data_in = data_in;
+    }
+    usb_mtp_queue_result(s, RES_OK, c->trans, nres, res0, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void usb_mtp_handle_reset(USBDevice *dev)
+{
+    MTPState *s = DO_UPCAST(MTPState, dev, dev);
+
+    trace_usb_mtp_reset(s->dev.addr);
+
+    s->session = 0;
+    usb_mtp_data_free(s->data_in);
+    s->data_in = NULL;
+    usb_mtp_data_free(s->data_out);
+    s->data_out = NULL;
+    g_free(s->result);
+    s->result = NULL;
+}
+
+static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p,
+                                   int request, int value, int index,
+                                   int length, uint8_t *data)
+{
+    int ret;
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return;
+    }
+
+    trace_usb_mtp_stall(dev->addr, "unknown control request");
+    p->status = USB_RET_STALL;
+}
+
+static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
+{
+    fprintf(stderr, "%s\n", __func__);
+}
+
+static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
+{
+    MTPState *s = DO_UPCAST(MTPState, dev, dev);
+    MTPControl cmd;
+    mtp_container container;
+    uint32_t params[5];
+    int i, rc;
+
+    switch (p->ep->nr) {
+    case EP_DATA_IN:
+        if (s->data_out != NULL) {
+            /* guest bug */
+            trace_usb_mtp_stall(s->dev.addr, "awaiting data-out");
+            p->status = USB_RET_STALL;
+            return;
+        }
+        if (p->iov.size < sizeof(container)) {
+            trace_usb_mtp_stall(s->dev.addr, "packet too small");
+            p->status = USB_RET_STALL;
+            return;
+        }
+        if (s->data_in !=  NULL) {
+            MTPData *d = s->data_in;
+            int dlen = d->length - d->offset;
+            if (d->first) {
+                trace_usb_mtp_data_in(s->dev.addr, d->trans, d->length);
+                container.length = cpu_to_le32(d->length + sizeof(container));
+                container.type   = cpu_to_le16(TYPE_DATA);
+                container.code   = cpu_to_le16(d->code);
+                container.trans  = cpu_to_le32(d->trans);
+                usb_packet_copy(p, &container, sizeof(container));
+                d->first = false;
+                if (dlen > p->iov.size - sizeof(container)) {
+                    dlen = p->iov.size - sizeof(container);
+                }
+            } else {
+                if (dlen > p->iov.size) {
+                    dlen = p->iov.size;
+                }
+            }
+            if (d->fd == -1) {
+                usb_packet_copy(p, d->data + d->offset, dlen);
+            } else {
+                if (d->alloc < p->iov.size) {
+                    d->alloc = p->iov.size;
+                    d->data = g_realloc(d->data, d->alloc);
+                }
+                rc = read(d->fd, d->data, dlen);
+                if (rc != dlen) {
+                    fprintf(stderr, "%s: TODO: handle read error\n", __func__);
+                }
+                usb_packet_copy(p, d->data, dlen);
+            }
+            d->offset += dlen;
+            if (d->offset == d->length) {
+                usb_mtp_data_free(s->data_in);
+                s->data_in = NULL;
+            }
+        } else if (s->result != NULL) {
+            MTPControl *r = s->result;
+            int length = sizeof(container) + r->argc * sizeof(uint32_t);
+            if (r->code == RES_OK) {
+                trace_usb_mtp_success(s->dev.addr, r->trans,
+                                      (r->argc > 0) ? r->argv[0] : 0,
+                                      (r->argc > 1) ? r->argv[1] : 0);
+            } else {
+                trace_usb_mtp_error(s->dev.addr, r->code, r->trans,
+                                    (r->argc > 0) ? r->argv[0] : 0,
+                                    (r->argc > 1) ? r->argv[1] : 0);
+            }
+            container.length = cpu_to_le32(length);
+            container.type   = cpu_to_le16(TYPE_RESPONSE);
+            container.code   = cpu_to_le16(r->code);
+            container.trans  = cpu_to_le32(r->trans);
+            for (i = 0; i < r->argc; i++) {
+                params[i] = cpu_to_le32(r->argv[i]);
+            }
+            usb_packet_copy(p, &container, sizeof(container));
+            usb_packet_copy(p, &params, length - sizeof(container));
+            g_free(s->result);
+            s->result = NULL;
+        }
+        break;
+    case EP_DATA_OUT:
+        if (p->iov.size < sizeof(container)) {
+            trace_usb_mtp_stall(s->dev.addr, "packet too small");
+            p->status = USB_RET_STALL;
+            return;
+        }
+        usb_packet_copy(p, &container, sizeof(container));
+        switch (le16_to_cpu(container.type)) {
+        case TYPE_COMMAND:
+            if (s->data_in || s->data_out || s->result) {
+                trace_usb_mtp_stall(s->dev.addr, "transaction inflight");
+                p->status = USB_RET_STALL;
+                return;
+            }
+            cmd.code = le16_to_cpu(container.code);
+            cmd.argc = (le32_to_cpu(container.length) - sizeof(container))
+                / sizeof(uint32_t);
+            cmd.trans = le32_to_cpu(container.trans);
+            usb_packet_copy(p, &params, cmd.argc * sizeof(uint32_t));
+            for (i = 0; i < cmd.argc; i++) {
+                cmd.argv[i] = le32_to_cpu(params[i]);
+            }
+            trace_usb_mtp_command(s->dev.addr, cmd.code, cmd.trans,
+                                  (cmd.argc > 0) ? cmd.argv[0] : 0,
+                                  (cmd.argc > 1) ? cmd.argv[1] : 0,
+                                  (cmd.argc > 2) ? cmd.argv[2] : 0,
+                                  (cmd.argc > 3) ? cmd.argv[3] : 0,
+                                  (cmd.argc > 4) ? cmd.argv[4] : 0);
+            usb_mtp_command(s, &cmd);
+            break;
+        default:
+            iov_hexdump(p->iov.iov, p->iov.niov, stderr, "mtp-out", 32);
+            trace_usb_mtp_stall(s->dev.addr, "TODO: implement data-out");
+            p->status = USB_RET_STALL;
+            return;
+        }
+        break;
+    case EP_EVENT:
+        p->status = USB_RET_NAK;
+        return;
+    default:
+        trace_usb_mtp_stall(s->dev.addr, "invalid endpoint");
+        p->status = USB_RET_STALL;
+        return;
+    }
+
+    if (p->actual_length == 0) {
+        trace_usb_mtp_nak(s->dev.addr, p->ep->nr);
+        p->status = USB_RET_NAK;
+        return;
+    } else {
+        trace_usb_mtp_xfer(s->dev.addr, p->ep->nr, p->actual_length,
+                           p->iov.size);
+        return;
+    }
+}
+
+static int usb_mtp_initfn(USBDevice *dev)
+{
+    MTPState *s = DO_UPCAST(MTPState, dev, dev);
+
+    usb_desc_create_serial(dev);
+    usb_desc_init(dev);
+    QTAILQ_INIT(&s->objects);
+    if (s->desc == NULL) {
+        s->desc = strrchr(s->root, '/');
+        if (s->desc) {
+            s->desc = g_strdup(s->desc + 1);
+        } else {
+            s->desc = g_strdup("none");
+        }
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_usb_mtp = {
+    .name = "usb-mtp",
+    .unmigratable = 1,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_USB_DEVICE(dev, MTPState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property mtp_properties[] = {
+    DEFINE_PROP_STRING("root", MTPState, root),
+    DEFINE_PROP_STRING("desc", MTPState, desc),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_mtp_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_mtp_initfn;
+    uc->product_desc   = "QEMU USB MTP";
+    uc->usb_desc       = &desc;
+    uc->cancel_packet  = usb_mtp_cancel_packet;
+    uc->handle_attach  = usb_desc_attach;
+    uc->handle_reset   = usb_mtp_handle_reset;
+    uc->handle_control = usb_mtp_handle_control;
+    uc->handle_data    = usb_mtp_handle_data;
+    dc->fw_name = "mtp";
+    dc->vmsd = &vmstate_usb_mtp;
+    dc->props = mtp_properties;
+}
+
+static TypeInfo mtp_info = {
+    .name          = "usb-mtp",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(MTPState),
+    .class_init    = usb_mtp_class_initfn,
+};
+
+static void usb_mtp_register_types(void)
+{
+    type_register_static(&mtp_info);
+}
+
+type_init(usb_mtp_register_types)
diff --git a/trace-events b/trace-events
index 9303245..6ecaab2 100644
--- a/trace-events
+++ b/trace-events
@@ -433,6 +433,27 @@ usb_uas_tmf_abort_task(int addr, uint16_t tag, uint16_t task_tag) "dev %d, tag 0
 usb_uas_tmf_logical_unit_reset(int addr, uint16_t tag, int lun) "dev %d, tag 0x%x, lun %d"
 usb_uas_tmf_unsupported(int addr, uint16_t tag, uint32_t function) "dev %d, tag 0x%x, function 0x%x"
 
+# hw/usb/dev-mtp.c
+usb_mtp_reset(int addr) "dev %d"
+usb_mtp_command(int dev, uint16_t code, uint32_t trans, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) "dev %d, code 0x%x, trans 0x%x, args 0x%x, 0x%x, 0x%x, 0x%x, 0x%x"
+usb_mtp_success(int dev, uint32_t trans, uint32_t arg0, uint32_t arg1) "dev %d, trans 0x%x, args 0x%x, 0x%x"
+usb_mtp_error(int dev, uint16_t code, uint32_t trans, uint32_t arg0, uint32_t arg1) "dev %d, code 0x%x, trans 0x%x, args 0x%x, 0x%x"
+usb_mtp_data_in(int dev, uint32_t trans, uint32_t len) "dev %d, trans 0x%x, len %d"
+usb_mtp_data_out(int dev, uint32_t trans, uint32_t len) "dev %d, trans 0x%x, len %d"
+usb_mtp_xfer(int dev, uint32_t ep, uint32_t dlen, uint32_t plen) "dev %d, ep %d, %d/%d"
+usb_mtp_nak(int dev, uint32_t ep) "dev %d, ep %d"
+usb_mtp_stall(int dev, const char *reason) "dev %d, reason: %s"
+usb_mtp_op_get_device_info(int dev) "dev %d"
+usb_mtp_op_open_session(int dev) "dev %d"
+usb_mtp_op_close_session(int dev) "dev %d"
+usb_mtp_op_get_storage_ids(int dev) "dev %d"
+usb_mtp_op_get_storage_info(int dev) "dev %d"
+usb_mtp_op_get_num_objects(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
+usb_mtp_op_get_object_handles(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
+usb_mtp_op_get_object_info(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
+usb_mtp_op_get_object(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
+usb_mtp_op_get_partial_object(int dev, uint32_t handle, const char *path, uint32_t offset, uint32_t length) "dev %d, handle 0x%x, path %s, off %d, len %d"
+
 # hw/usb/host-libusb.c
 usb_host_open_started(int bus, int addr) "dev %d:%d"
 usb_host_open_success(int bus, int addr) "dev %d:%d"
commit 409951f552674a940ec53e3a498514dc42834ccb
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Mar 18 11:01:50 2014 +0100

    usb: add CompatibleID support to msos
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/desc-msos.c b/hw/usb/desc-msos.c
index ed8d62c..334d1ae 100644
--- a/hw/usb/desc-msos.c
+++ b/hw/usb/desc-msos.c
@@ -44,7 +44,7 @@ typedef struct msos_compat_hdr {
 typedef struct msos_compat_func {
     uint8_t  bFirstInterfaceNumber;
     uint8_t  reserved_1;
-    uint8_t  compatibleId[8];
+    char     compatibleId[8];
     uint8_t  subCompatibleId[8];
     uint8_t  reserved_2[6];
 } QEMU_PACKED msos_compat_func;
@@ -59,6 +59,10 @@ static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest)
     func = (void *)(dest + length);
     func->bFirstInterfaceNumber = 0;
     func->reserved_1 = 0x01;
+    if (desc->msos->CompatibleID) {
+        snprintf(func->compatibleId, sizeof(func->compatibleId),
+                 "%s", desc->msos->CompatibleID);
+    }
     length += sizeof(*func);
     count++;
 
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 2b4fcda..8e8db03 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -184,6 +184,7 @@ struct USBDescOther {
 };
 
 struct USBDescMSOS {
+    const char                *CompatibleID;
     const wchar_t             *Label;
     bool                      SelectiveSuspendEnabled;
 };
commit 02eb19d0ec19ac8fb1de1116999184663763eaa0
Author: Richard Henderson <rth at twiddle.net>
Date:   Mon Mar 31 14:09:13 2014 -0700

    tcg: Use HOST_WORDS_BIGENDIAN
    
    Instead of rolling a local TCG_TARGET_WORDS_BIGENDIAN.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index adf0261..eff1d68 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -13,7 +13,6 @@
 #ifndef TCG_TARGET_AARCH64
 #define TCG_TARGET_AARCH64 1
 
-#undef TCG_TARGET_WORDS_BIGENDIAN
 #undef TCG_TARGET_STACK_GROWSUP
 
 typedef enum {
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 35de34e..1bc5dac 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -25,7 +25,6 @@
 #ifndef TCG_TARGET_ARM 
 #define TCG_TARGET_ARM 1
 
-#undef TCG_TARGET_WORDS_BIGENDIAN
 #undef TCG_TARGET_STACK_GROWSUP
 
 typedef enum {
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index bdf2222..ababca0 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -24,8 +24,6 @@
 #ifndef TCG_TARGET_I386 
 #define TCG_TARGET_I386 1
 
-#undef TCG_TARGET_WORDS_BIGENDIAN
-
 #ifdef __x86_64__
 # define TCG_TARGET_REG_BITS  64
 # define TCG_TARGET_NB_REGS   16
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 76bc222..37241b2 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -26,7 +26,7 @@
 
 #include "tcg-be-null.h"
 
-#if defined(TCG_TARGET_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
 # define TCG_NEED_BSWAP 0
 #else
 # define TCG_NEED_BSWAP 1
@@ -589,7 +589,7 @@ static inline void tcg_out_call_iarg_reg64(TCGContext *s, int *arg_num,
 {
     (*arg_num) = (*arg_num + 1) & ~1;
 
-#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+#if defined(HOST_WORDS_BIGENDIAN)
     tcg_out_call_iarg_reg32(s, arg_num, arg_high);
     tcg_out_call_iarg_reg32(s, arg_num, arg_low);
 #else
@@ -964,7 +964,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
 #if defined(CONFIG_SOFTMMU)
 # if TARGET_LONG_BITS == 64
     addr_regh = *args++;
-#  if defined(TCG_TARGET_WORDS_BIGENDIAN)
+#  if defined(HOST_WORDS_BIGENDIAN)
     addr_memh = 0;
     addr_meml = 4;
 #  else
@@ -979,7 +979,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
 #endif
 
     if (opc == 3) {
-#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+#if defined(HOST_WORDS_BIGENDIAN)
         data_reg1 = data_regh;
         data_reg2 = data_regl;
 #else
@@ -1152,7 +1152,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
 #if defined(CONFIG_SOFTMMU)
 # if TARGET_LONG_BITS == 64
     addr_regh = *args++;
-#  if defined(TCG_TARGET_WORDS_BIGENDIAN)
+#  if defined(HOST_WORDS_BIGENDIAN)
     addr_memh = 0;
     addr_meml = 4;
 #  else
@@ -1167,7 +1167,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
 #endif
 
     if (opc == 3) {
-#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+#if defined(HOST_WORDS_BIGENDIAN)
         data_reg1 = data_regh;
         data_reg2 = data_regl;
 #else
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index c3822d0..9576db5 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -26,10 +26,6 @@
 #ifndef TCG_TARGET_MIPS 
 #define TCG_TARGET_MIPS 1
 
-#ifdef __MIPSEB__
-# define TCG_TARGET_WORDS_BIGENDIAN
-#endif
-
 #define TCG_TARGET_NB_REGS 32
 
 typedef enum {
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 1168912..0d4f595 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -24,7 +24,6 @@
 #ifndef TCG_TARGET_PPC 
 #define TCG_TARGET_PPC 1
 
-#define TCG_TARGET_WORDS_BIGENDIAN
 #define TCG_TARGET_NB_REGS 32
 
 typedef enum {
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
index 7ee50b6..78bbf7a 100644
--- a/tcg/ppc64/tcg-target.h
+++ b/tcg/ppc64/tcg-target.h
@@ -24,7 +24,6 @@
 #ifndef TCG_TARGET_PPC64 
 #define TCG_TARGET_PPC64 1
 
-#define TCG_TARGET_WORDS_BIGENDIAN
 #define TCG_TARGET_NB_REGS 32
 
 typedef enum {
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index 10adb77..b3bfdcc 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -24,8 +24,6 @@
 #ifndef TCG_TARGET_S390 
 #define TCG_TARGET_S390 1
 
-#define TCG_TARGET_WORDS_BIGENDIAN
-
 typedef enum TCGReg {
     TCG_REG_R0 = 0,
     TCG_REG_R1,
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 3abf1b4..4519c64 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -32,8 +32,6 @@
 # error Unknown pointer size for tcg target
 #endif
 
-#define TCG_TARGET_WORDS_BIGENDIAN
-
 #define TCG_TARGET_NB_REGS 32
 
 typedef enum {
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index d43f45d..8d4ff7d 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -858,7 +858,7 @@ static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2,
 {
     /* since arg2 and ret have different types, they cannot be the
        same temporary */
-#ifdef TCG_TARGET_WORDS_BIGENDIAN
+#ifdef HOST_WORDS_BIGENDIAN
     tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset);
     tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4);
 #else
@@ -888,7 +888,7 @@ static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2,
 static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2,
                                   tcg_target_long offset)
 {
-#ifdef TCG_TARGET_WORDS_BIGENDIAN
+#ifdef HOST_WORDS_BIGENDIAN
     tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset);
     tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4);
 #else
diff --git a/tcg/tcg.c b/tcg/tcg.c
index d92ecb3..21ce9fb 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -444,7 +444,7 @@ static inline int tcg_global_mem_new_internal(TCGType type, int reg,
         ts->fixed_reg = 0;
         ts->mem_allocated = 1;
         ts->mem_reg = reg;
-#ifdef TCG_TARGET_WORDS_BIGENDIAN
+#ifdef HOST_WORDS_BIGENDIAN
         ts->mem_offset = offset + 4;
 #else
         ts->mem_offset = offset;
@@ -459,7 +459,7 @@ static inline int tcg_global_mem_new_internal(TCGType type, int reg,
         ts->fixed_reg = 0;
         ts->mem_allocated = 1;
         ts->mem_reg = reg;
-#ifdef TCG_TARGET_WORDS_BIGENDIAN
+#ifdef HOST_WORDS_BIGENDIAN
         ts->mem_offset = offset;
 #else
         ts->mem_offset = offset + 4;
@@ -686,7 +686,7 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
     if (ret != TCG_CALL_DUMMY_ARG) {
 #if TCG_TARGET_REG_BITS < 64
         if (sizemask & 1) {
-#ifdef TCG_TARGET_WORDS_BIGENDIAN
+#ifdef HOST_WORDS_BIGENDIAN
             *s->gen_opparam_ptr++ = ret + 1;
             *s->gen_opparam_ptr++ = ret;
 #else
@@ -725,7 +725,7 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
 	       order.  If another such target is added, this logic may
 	       have to get more complicated to differentiate between
 	       stack arguments and register arguments.  */
-#if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
             *s->gen_opparam_ptr++ = args[i] + 1;
             *s->gen_opparam_ptr++ = args[i];
 #else
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index 7869119..f43492c 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -57,12 +57,6 @@
 #define CONFIG_DEBUG_TCG_INTERPRETER
 #endif
 
-#if 0 /* TCI tries to emulate a little endian host. */
-#if defined(HOST_WORDS_BIGENDIAN)
-# define TCG_TARGET_WORDS_BIGENDIAN
-#endif
-#endif
-
 /* Optional instructions. */
 
 #define TCG_TARGET_HAS_bswap16_i32      1
commit 662deb908f72a0282c4c2fdb9f62f9f484c62e5b
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Mar 26 11:09:44 2014 -0700

    tcg: Fix fallback from muls2_i64 to mulu2_i64
    
    Brown Bag sez, don't put the fallback code into the wrong function.
    Also, check for muluh_i64 and use tcg_gen_mulu2_i64 instead of raw ops.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 08dd09e..d43f45d 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -2520,26 +2520,6 @@ static inline void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh,
         tcg_gen_op3_i64(INDEX_op_muluh_i64, rh, arg1, arg2);
         tcg_gen_mov_i64(rl, t);
         tcg_temp_free_i64(t);
-    } 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;
@@ -2567,6 +2547,24 @@ static inline void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh,
         tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2);
         tcg_gen_mov_i64(rl, t);
         tcg_temp_free_i64(t);
+    } else if (TCG_TARGET_HAS_mulu2_i64 || TCG_TARGET_HAS_muluh_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_mulu2_i64(t0, t1, arg1, arg2);
+        /* 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;
commit f46fc4e6a953e78b283834f67bc338bd35d7d316
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Mar 26 11:01:30 2014 -0700

    tcg: Use tcg_gen_mulu2_i32 in tcg_gen_muls2_i32
    
    Rather than hard-coding use of mulu2_i32, allow muluh_i32.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 7eabf22..08dd09e 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -2437,14 +2437,12 @@ static inline void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh,
         tcg_gen_op3_i32(INDEX_op_mulsh_i32, rh, arg1, arg2);
         tcg_gen_mov_i32(rl, t);
         tcg_temp_free_i32(t);
-    } else if (TCG_TARGET_REG_BITS == 32 && TCG_TARGET_HAS_mulu2_i32) {
+    } else if (TCG_TARGET_REG_BITS == 32) {
         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);
+        tcg_gen_mulu2_i32(t0, t1, arg1, arg2);
         /* Adjust for negative inputs.  */
         tcg_gen_sari_i32(t2, arg1, 31);
         tcg_gen_sari_i32(t3, arg2, 31);
commit df9ebea53ebc1c98217743f56c30ae3a46031bb9
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Mar 26 10:59:14 2014 -0700

    tcg: Relax requirement for mulu2_i32 on 32-bit hosts
    
    Instead require either mulu2_i32 or muluh_i32.  The code in tcg-op.h
    already supports looking for both.  Previous incomplete conversion?
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 3746b6e..35de34e 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -79,6 +79,7 @@ extern bool use_idiv_instructions;
 #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_mulu2_i32        1
 #define TCG_TARGET_HAS_muls2_i32        1
 #define TCG_TARGET_HAS_muluh_i32        0
 #define TCG_TARGET_HAS_mulsh_i32        0
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index 683c6af..c3822d0 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -109,6 +109,7 @@ extern bool use_mips32r2_instructions;
 #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_mulu2_i32        1
 #define TCG_TARGET_HAS_muls2_i32        1
 #define TCG_TARGET_HAS_muluh_i32        1
 #define TCG_TARGET_HAS_mulsh_i32        1
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index e3395e3..1168912 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -95,6 +95,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_mulu2_i32        1
 #define TCG_TARGET_HAS_muls2_i32        0
 #define TCG_TARGET_HAS_muluh_i32        0
 #define TCG_TARGET_HAS_mulsh_i32        0
diff --git a/tcg/tcg.h b/tcg/tcg.h
index f7efcb4..0bb6677 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -97,7 +97,6 @@ typedef uint64_t TCGRegSet;
 /* 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
@@ -121,6 +120,13 @@ typedef uint64_t TCGRegSet;
 #define TCG_TARGET_HAS_rem_i64          0
 #endif
 
+/* For 32-bit targets, some sort of unsigned widening multiply is required.  */
+#if TCG_TARGET_REG_BITS == 32 \
+    && !(defined(TCG_TARGET_HAS_mulu2_i32) \
+         || defined(TCG_TARGET_HAS_muluh_i32))
+# error "Missing unsigned widening multiply"
+#endif
+
 typedef enum TCGOpcode {
 #define DEF(name, oargs, iargs, cargs, flags) INDEX_op_ ## name,
 #include "tcg-opc.h"
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index 6e1da8c..7869119 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -118,6 +118,8 @@
 #define TCG_TARGET_HAS_mulu2_i64        0
 #define TCG_TARGET_HAS_muluh_i64        0
 #define TCG_TARGET_HAS_mulsh_i64        0
+#else
+#define TCG_TARGET_HAS_mulu2_i32        1
 #endif /* TCG_TARGET_REG_BITS == 64 */
 
 #define TCG_TARGET_HAS_new_ldst         0
commit 671c835b7dc12bfb3907c6af38f74073fe8fade9
Author: Richard Henderson <rth at twiddle.net>
Date:   Mon Mar 31 02:25:26 2014 -0400

    tcg-s390: Remove W constraint
    
    Now redundant with the type parameter to tcg_target_const_match.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index feeaf97..1d912a7 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -38,11 +38,10 @@
    a 32-bit displacement here Just In Case.  */
 #define USE_LONG_BRANCHES 0
 
-#define TCG_CT_CONST_32    0x0100
-#define TCG_CT_CONST_MULI  0x0800
-#define TCG_CT_CONST_ORI   0x2000
-#define TCG_CT_CONST_XORI  0x4000
-#define TCG_CT_CONST_CMPI  0x8000
+#define TCG_CT_CONST_MULI  0x100
+#define TCG_CT_CONST_ORI   0x200
+#define TCG_CT_CONST_XORI  0x400
+#define TCG_CT_CONST_CMPI  0x800
 
 /* Several places within the instruction set 0 means "no register"
    rather than TCG_REG_R0.  */
@@ -407,9 +406,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
         tcg_regset_clear(ct->u.regs);
         tcg_regset_set_reg(ct->u.regs, TCG_REG_R3);
         break;
-    case 'W':                  /* force 32-bit ("word") immediate */
-        ct->ct |= TCG_CT_CONST_32;
-        break;
     case 'K':
         ct->ct |= TCG_CT_CONST_MULI;
         break;
@@ -437,10 +433,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
    can load efficiently, and the immediate load plus the reg-reg OR is
    smaller than the sequential OI's.  */
 
-static int tcg_match_ori(int ct, tcg_target_long val)
+static int tcg_match_ori(TCGType type, tcg_target_long val)
 {
     if (facilities & FACILITY_EXT_IMM) {
-        if (ct & TCG_CT_CONST_32) {
+        if (type == TCG_TYPE_I32) {
             /* All 32-bit ORs can be performed with 1 48-bit insn.  */
             return 1;
         }
@@ -466,13 +462,13 @@ static int tcg_match_ori(int ct, tcg_target_long val)
    extended-immediate facility.  That said, there are a few patterns for
    which it is better to load the value into a register first.  */
 
-static int tcg_match_xori(int ct, tcg_target_long val)
+static int tcg_match_xori(TCGType type, tcg_target_long val)
 {
     if ((facilities & FACILITY_EXT_IMM) == 0) {
         return 0;
     }
 
-    if (ct & TCG_CT_CONST_32) {
+    if (type == TCG_TYPE_I32) {
         /* All 32-bit XORs can be performed with 1 48-bit insn.  */
         return 1;
     }
@@ -487,11 +483,11 @@ static int tcg_match_xori(int ct, tcg_target_long val)
 
 /* Imediates to be used with comparisons.  */
 
-static int tcg_match_cmpi(int ct, tcg_target_long val)
+static int tcg_match_cmpi(TCGType type, tcg_target_long val)
 {
     if (facilities & FACILITY_EXT_IMM) {
         /* The COMPARE IMMEDIATE instruction is available.  */
-        if (ct & TCG_CT_CONST_32) {
+        if (type == TCG_TYPE_I32) {
             /* We have a 32-bit immediate and can compare against anything.  */
             return 1;
         } else {
@@ -524,8 +520,7 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
         return 1;
     }
 
-    /* Handle the modifiers.  */
-    if (ct & TCG_CT_CONST_32) {
+    if (type == TCG_TYPE_I32) {
         val = (int32_t)val;
     }
 
@@ -541,11 +536,11 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
             return val == (int16_t)val;
         }
     } else if (ct & TCG_CT_CONST_ORI) {
-        return tcg_match_ori(ct, val);
+        return tcg_match_ori(type, val);
     } else if (ct & TCG_CT_CONST_XORI) {
-        return tcg_match_xori(ct, val);
+        return tcg_match_xori(type, val);
     } else if (ct & TCG_CT_CONST_CMPI) {
-        return tcg_match_cmpi(ct, val);
+        return tcg_match_cmpi(type, val);
     }
 
     return 0;
@@ -2112,8 +2107,8 @@ static const TCGTargetOpDef s390_op_defs[] = {
     { INDEX_op_divu2_i32, { "b", "a", "0", "1", "r" } },
 
     { INDEX_op_and_i32, { "r", "0", "ri" } },
-    { INDEX_op_or_i32, { "r", "0", "rWO" } },
-    { INDEX_op_xor_i32, { "r", "0", "rWX" } },
+    { INDEX_op_or_i32, { "r", "0", "rO" } },
+    { INDEX_op_xor_i32, { "r", "0", "rX" } },
 
     { INDEX_op_neg_i32, { "r", "r" } },
 
@@ -2135,9 +2130,9 @@ static const TCGTargetOpDef s390_op_defs[] = {
     { INDEX_op_add2_i32, { "r", "r", "0", "1", "r", "r" } },
     { INDEX_op_sub2_i32, { "r", "r", "0", "1", "r", "r" } },
 
-    { INDEX_op_brcond_i32, { "r", "rWC" } },
-    { INDEX_op_setcond_i32, { "r", "r", "rWC" } },
-    { INDEX_op_movcond_i32, { "r", "r", "rWC", "r", "0" } },
+    { INDEX_op_brcond_i32, { "r", "rC" } },
+    { INDEX_op_setcond_i32, { "r", "r", "rC" } },
+    { INDEX_op_movcond_i32, { "r", "r", "rC", "r", "0" } },
     { INDEX_op_deposit_i32, { "r", "0", "r" } },
 
     { INDEX_op_qemu_ld8u, { "r", "L" } },
commit 4b304cfae13e66d95de8bb67ce769881fc3a3f1b
Author: Richard Henderson <rth at twiddle.net>
Date:   Sun Mar 30 22:27:35 2014 -0700

    tcg-sparc: Use the type parameter to tcg_target_const_match
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 73121e1..35089b8 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -334,7 +334,13 @@ static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
 
     if (ct & TCG_CT_CONST) {
         return 1;
-    } else if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
+    }
+
+    if (type == TCG_TYPE_I32) {
+        val = (int32_t)val;
+    }
+
+    if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
         return 1;
     } else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11)) {
         return 1;
commit 1194dcba22a1dbd9fb797fa087bd8f8ab0cb377e
Author: Richard Henderson <rth at twiddle.net>
Date:   Sun Mar 30 22:07:27 2014 -0700

    tcg-ppc64: Use the type parameter to tcg_target_const_match
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index a533698..45b1c06 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -296,7 +296,15 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
     int ct = arg_ct->ct;
     if (ct & TCG_CT_CONST) {
         return 1;
-    } else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) {
+    }
+
+    /* The only 32-bit constraint we use aside from
+       TCG_CT_CONST is TCG_CT_CONST_S16.  */
+    if (type == TCG_TYPE_I32) {
+        val = (int32_t)val;
+    }
+
+    if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) {
         return 1;
     } else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val) {
         return 1;
commit 170bf9315b352ce56aafa9785eea441b326ed5b7
Author: Richard Henderson <rth at twiddle.net>
Date:   Sun Mar 30 21:26:34 2014 -0700

    tcg-aarch64: Remove w constraint
    
    Now redundant with the type parameter to tcg_target_const_match.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c
index 4d2e956..0a580b6 100644
--- a/tcg/aarch64/tcg-target.c
+++ b/tcg/aarch64/tcg-target.c
@@ -102,11 +102,10 @@ static inline void patch_reloc(uint8_t *code_ptr, int type,
     }
 }
 
-#define TCG_CT_CONST_IS32 0x100
-#define TCG_CT_CONST_AIMM 0x200
-#define TCG_CT_CONST_LIMM 0x400
-#define TCG_CT_CONST_ZERO 0x800
-#define TCG_CT_CONST_MONE 0x1000
+#define TCG_CT_CONST_AIMM 0x100
+#define TCG_CT_CONST_LIMM 0x200
+#define TCG_CT_CONST_ZERO 0x400
+#define TCG_CT_CONST_MONE 0x800
 
 /* parse target specific constraints */
 static int target_parse_constraint(TCGArgConstraint *ct,
@@ -131,9 +130,6 @@ static int target_parse_constraint(TCGArgConstraint *ct,
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_X3);
 #endif
         break;
-    case 'w': /* The operand should be considered 32-bit.  */
-        ct->ct |= TCG_CT_CONST_IS32;
-        break;
     case 'A': /* Valid for arithmetic immediate (positive or negative).  */
         ct->ct |= TCG_CT_CONST_AIMM;
         break;
@@ -188,7 +184,7 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
     if (ct & TCG_CT_CONST) {
         return 1;
     }
-    if (ct & TCG_CT_CONST_IS32) {
+    if (type == TCG_TYPE_I32) {
         val = (int32_t)val;
     }
     if ((ct & TCG_CT_CONST_AIMM) && (is_aimm(val) || is_aimm(-val))) {
@@ -1663,9 +1659,9 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
     { INDEX_op_st32_i64, { "rZ", "r" } },
     { INDEX_op_st_i64, { "rZ", "r" } },
 
-    { INDEX_op_add_i32, { "r", "r", "rwA" } },
+    { INDEX_op_add_i32, { "r", "r", "rA" } },
     { INDEX_op_add_i64, { "r", "r", "rA" } },
-    { INDEX_op_sub_i32, { "r", "r", "rwA" } },
+    { INDEX_op_sub_i32, { "r", "r", "rA" } },
     { INDEX_op_sub_i64, { "r", "r", "rA" } },
     { INDEX_op_mul_i32, { "r", "r", "r" } },
     { INDEX_op_mul_i64, { "r", "r", "r" } },
@@ -1677,17 +1673,17 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
     { INDEX_op_rem_i64, { "r", "r", "r" } },
     { INDEX_op_remu_i32, { "r", "r", "r" } },
     { INDEX_op_remu_i64, { "r", "r", "r" } },
-    { INDEX_op_and_i32, { "r", "r", "rwL" } },
+    { INDEX_op_and_i32, { "r", "r", "rL" } },
     { INDEX_op_and_i64, { "r", "r", "rL" } },
-    { INDEX_op_or_i32, { "r", "r", "rwL" } },
+    { INDEX_op_or_i32, { "r", "r", "rL" } },
     { INDEX_op_or_i64, { "r", "r", "rL" } },
-    { INDEX_op_xor_i32, { "r", "r", "rwL" } },
+    { INDEX_op_xor_i32, { "r", "r", "rL" } },
     { INDEX_op_xor_i64, { "r", "r", "rL" } },
-    { INDEX_op_andc_i32, { "r", "r", "rwL" } },
+    { INDEX_op_andc_i32, { "r", "r", "rL" } },
     { INDEX_op_andc_i64, { "r", "r", "rL" } },
-    { INDEX_op_orc_i32, { "r", "r", "rwL" } },
+    { INDEX_op_orc_i32, { "r", "r", "rL" } },
     { INDEX_op_orc_i64, { "r", "r", "rL" } },
-    { INDEX_op_eqv_i32, { "r", "r", "rwL" } },
+    { INDEX_op_eqv_i32, { "r", "r", "rL" } },
     { INDEX_op_eqv_i64, { "r", "r", "rL" } },
 
     { INDEX_op_neg_i32, { "r", "r" } },
@@ -1706,11 +1702,11 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
     { INDEX_op_rotl_i64, { "r", "r", "ri" } },
     { INDEX_op_rotr_i64, { "r", "r", "ri" } },
 
-    { INDEX_op_brcond_i32, { "r", "rwA" } },
+    { INDEX_op_brcond_i32, { "r", "rA" } },
     { INDEX_op_brcond_i64, { "r", "rA" } },
-    { INDEX_op_setcond_i32, { "r", "r", "rwA" } },
+    { INDEX_op_setcond_i32, { "r", "r", "rA" } },
     { INDEX_op_setcond_i64, { "r", "r", "rA" } },
-    { INDEX_op_movcond_i32, { "r", "r", "rwA", "rZ", "rZ" } },
+    { INDEX_op_movcond_i32, { "r", "r", "rA", "rZ", "rZ" } },
     { INDEX_op_movcond_i64, { "r", "r", "rA", "rZ", "rZ" } },
 
     { INDEX_op_qemu_ld_i32, { "r", "l" } },
@@ -1739,9 +1735,9 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
     { INDEX_op_deposit_i32, { "r", "0", "rZ" } },
     { INDEX_op_deposit_i64, { "r", "0", "rZ" } },
 
-    { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rwA", "rwMZ" } },
+    { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rA", "rMZ" } },
     { INDEX_op_add2_i64, { "r", "r", "rZ", "rZ", "rA", "rMZ" } },
-    { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rwA", "rwMZ" } },
+    { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rA", "rMZ" } },
     { INDEX_op_sub2_i64, { "r", "r", "rZ", "rZ", "rA", "rMZ" } },
 
     { INDEX_op_muluh_i64, { "r", "r", "r" } },
commit f6c6afc1d41bf53394df15f62b25f15e1de72614
Author: Richard Henderson <rth at twiddle.net>
Date:   Sun Mar 30 21:22:11 2014 -0700

    tcg: Add TCGType parameter to tcg_target_const_match
    
    Most 64-bit targets need to be able to ignore the high bits
    of a TCG_TYPE_I32 value.
    
    Suggested-by: Stuart Brady <sdb at zubnet.me.uk>
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c
index d5500ff..4d2e956 100644
--- a/tcg/aarch64/tcg-target.c
+++ b/tcg/aarch64/tcg-target.c
@@ -180,7 +180,7 @@ static inline bool is_limm(uint64_t val)
     return (val & (val - 1)) == 0;
 }
 
-static int tcg_target_const_match(tcg_target_long val,
+static int tcg_target_const_match(tcg_target_long val, TCGType type,
                                   const TCGArgConstraint *arg_ct)
 {
     int ct = arg_ct->ct;
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 5a09226..7535175 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -261,7 +261,7 @@ static inline int check_fit_imm(uint32_t imm)
  * mov operand2:     values represented with x << (2 * y), x < 0x100
  * add, sub, eor...: ditto
  */
-static inline int tcg_target_const_match(tcg_target_long val,
+static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
                                          const TCGArgConstraint *arg_ct)
 {
     int ct;
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 0c2347c..34ece1f 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -257,7 +257,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 }
 
 /* test if a constant matches the constraint */
-static inline int tcg_target_const_match(tcg_target_long val,
+static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
                                          const TCGArgConstraint *arg_ct)
 {
     int ct = arg_ct->ct;
diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 2d8e00c..c640184 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -832,7 +832,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 }
 
 /* test if a constant matches the constraint */
-static inline int tcg_target_const_match(tcg_target_long val,
+static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
                                          const TCGArgConstraint *arg_ct)
 {
     int ct;
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 40551cd..76bc222 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -253,7 +253,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 }
 
 /* test if a constant matches the constraint */
-static inline int tcg_target_const_match(tcg_target_long val,
+static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
                                          const TCGArgConstraint *arg_ct)
 {
     int ct;
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 06bedd9..83d9340 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -298,7 +298,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 }
 
 /* test if a constant matches the constraint */
-static int tcg_target_const_match(tcg_target_long val,
+static int tcg_target_const_match(tcg_target_long val, TCGType type,
                                   const TCGArgConstraint *arg_ct)
 {
     int ct;
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index 06e440f..a533698 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -290,7 +290,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 }
 
 /* test if a constant matches the constraint */
-static int tcg_target_const_match(tcg_target_long val,
+static int tcg_target_const_match(tcg_target_long val, TCGType type,
                                   const TCGArgConstraint *arg_ct)
 {
     int ct = arg_ct->ct;
diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 907d9d1..feeaf97 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -515,7 +515,7 @@ static int tcg_match_cmpi(int ct, tcg_target_long val)
 }
 
 /* Test if a constant matches the constraint. */
-static int tcg_target_const_match(tcg_target_long val,
+static int tcg_target_const_match(tcg_target_long val, TCGType type,
                                   const TCGArgConstraint *arg_ct)
 {
     int ct = arg_ct->ct;
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 152335c..73121e1 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -327,7 +327,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 }
 
 /* test if a constant matches the constraint */
-static inline int tcg_target_const_match(tcg_target_long val,
+static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
                                          const TCGArgConstraint *arg_ct)
 {
     int ct = arg_ct->ct;
diff --git a/tcg/tcg.c b/tcg/tcg.c
index f1e0763..d92ecb3 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -101,7 +101,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
                        const int *const_args);
 static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
                        intptr_t arg2);
-static int tcg_target_const_match(tcg_target_long val,
+static int tcg_target_const_match(tcg_target_long val, TCGType type,
                                   const TCGArgConstraint *arg_ct);
 static void tcg_out_tb_init(TCGContext *s);
 static void tcg_out_tb_finalize(TCGContext *s);
@@ -2121,7 +2121,7 @@ static void tcg_reg_alloc_op(TCGContext *s,
             ts->mem_coherent = 1;
             s->reg_to_temp[reg] = arg;
         } else if (ts->val_type == TEMP_VAL_CONST) {
-            if (tcg_target_const_match(ts->val, arg_ct)) {
+            if (tcg_target_const_match(ts->val, ts->type, arg_ct)) {
                 /* constant is OK for instruction */
                 const_args[i] = 1;
                 new_args[i] = ts->val;
@@ -2365,7 +2365,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
         func_arg = reg;
         tcg_regset_set_reg(allocated_regs, reg);
     } else if (ts->val_type == TEMP_VAL_CONST) {
-        if (tcg_target_const_match(func_addr, arg_ct)) {
+        if (tcg_target_const_match(func_addr, ts->type, arg_ct)) {
             const_func_arg = 1;
             func_arg = func_addr;
         } else {
diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c
index fc80704..47c0b85 100644
--- a/tcg/tci/tcg-target.c
+++ b/tcg/tci/tcg-target.c
@@ -859,7 +859,7 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
 }
 
 /* Test if a constant matches the constraint. */
-static int tcg_target_const_match(tcg_target_long val,
+static int tcg_target_const_match(tcg_target_long val, TCGType type,
                                   const TCGArgConstraint *arg_ct)
 {
     /* No need to return 0 or 1, 0 or != 0 is good enough. */
commit d998e555d2a504d719b773b3164101aa36284a20
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Mar 18 14:23:52 2014 -0700

    tcg: Fix out of range shift in deposit optimizations
    
    By inspection, for a deposit(x, y, 0, 64), we'd have a shift of (1<<64)
    and everything else falls apart.  But we can reuse the existing deposit
    logic to get this right.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/optimize.c b/tcg/optimize.c
index 2fb708e..c447062 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -843,9 +843,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
             break;
 
         CASE_OP_32_64(deposit):
-            tmp = ((1ull << args[4]) - 1);
-            mask = ((temps[args[1]].mask & ~(tmp << args[3]))
-                    | ((temps[args[2]].mask & tmp) << args[3]));
+            mask = deposit64(temps[args[1]].mask, args[3], args[4],
+                             temps[args[2]].mask);
             break;
 
         CASE_OP_32_64(or):
@@ -1060,9 +1059,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
             if (temps[args[1]].state == TCG_TEMP_CONST
                 && temps[args[2]].state == TCG_TEMP_CONST) {
                 s->gen_opc_buf[op_index] = op_to_movi(op);
-                tmp = ((1ull << args[4]) - 1);
-                tmp = (temps[args[1]].val & ~(tmp << args[3]))
-                      | ((temps[args[2]].val & tmp) << args[3]);
+                tmp = deposit64(temps[args[1]].val, args[3], args[4],
+                                temps[args[2]].val);
                 tcg_opt_gen_movi(gen_args, args[0], tmp);
                 gen_args += 2;
                 args += 5;
commit 1976cccec8a9965ff3fd6f026783a04f6b4959fd
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Mar 18 08:44:05 2014 -0700

    tci: Mask shift counts to avoid undefined behavior
    
    TCG now requires unspecified behavior rather than a potential crash,
    bring the C shift within the letter of the law.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tci.c b/tci.c
index 0202ed9..6523ab8 100644
--- a/tci.c
+++ b/tci.c
@@ -669,32 +669,32 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
             t0 = *tb_ptr++;
             t1 = tci_read_ri32(&tb_ptr);
             t2 = tci_read_ri32(&tb_ptr);
-            tci_write_reg32(t0, t1 << t2);
+            tci_write_reg32(t0, t1 << (t2 & 31));
             break;
         case INDEX_op_shr_i32:
             t0 = *tb_ptr++;
             t1 = tci_read_ri32(&tb_ptr);
             t2 = tci_read_ri32(&tb_ptr);
-            tci_write_reg32(t0, t1 >> t2);
+            tci_write_reg32(t0, t1 >> (t2 & 31));
             break;
         case INDEX_op_sar_i32:
             t0 = *tb_ptr++;
             t1 = tci_read_ri32(&tb_ptr);
             t2 = tci_read_ri32(&tb_ptr);
-            tci_write_reg32(t0, ((int32_t)t1 >> t2));
+            tci_write_reg32(t0, ((int32_t)t1 >> (t2 & 31)));
             break;
 #if TCG_TARGET_HAS_rot_i32
         case INDEX_op_rotl_i32:
             t0 = *tb_ptr++;
             t1 = tci_read_ri32(&tb_ptr);
             t2 = tci_read_ri32(&tb_ptr);
-            tci_write_reg32(t0, rol32(t1, t2));
+            tci_write_reg32(t0, rol32(t1, t2 & 31));
             break;
         case INDEX_op_rotr_i32:
             t0 = *tb_ptr++;
             t1 = tci_read_ri32(&tb_ptr);
             t2 = tci_read_ri32(&tb_ptr);
-            tci_write_reg32(t0, ror32(t1, t2));
+            tci_write_reg32(t0, ror32(t1, t2 & 31));
             break;
 #endif
 #if TCG_TARGET_HAS_deposit_i32
@@ -936,32 +936,32 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
             t0 = *tb_ptr++;
             t1 = tci_read_ri64(&tb_ptr);
             t2 = tci_read_ri64(&tb_ptr);
-            tci_write_reg64(t0, t1 << t2);
+            tci_write_reg64(t0, t1 << (t2 & 63));
             break;
         case INDEX_op_shr_i64:
             t0 = *tb_ptr++;
             t1 = tci_read_ri64(&tb_ptr);
             t2 = tci_read_ri64(&tb_ptr);
-            tci_write_reg64(t0, t1 >> t2);
+            tci_write_reg64(t0, t1 >> (t2 & 63));
             break;
         case INDEX_op_sar_i64:
             t0 = *tb_ptr++;
             t1 = tci_read_ri64(&tb_ptr);
             t2 = tci_read_ri64(&tb_ptr);
-            tci_write_reg64(t0, ((int64_t)t1 >> t2));
+            tci_write_reg64(t0, ((int64_t)t1 >> (t2 & 63)));
             break;
 #if TCG_TARGET_HAS_rot_i64
         case INDEX_op_rotl_i64:
             t0 = *tb_ptr++;
             t1 = tci_read_ri64(&tb_ptr);
             t2 = tci_read_ri64(&tb_ptr);
-            tci_write_reg64(t0, rol64(t1, t2));
+            tci_write_reg64(t0, rol64(t1, t2 & 63));
             break;
         case INDEX_op_rotr_i64:
             t0 = *tb_ptr++;
             t1 = tci_read_ri64(&tb_ptr);
             t2 = tci_read_ri64(&tb_ptr);
-            tci_write_reg64(t0, ror64(t1, t2));
+            tci_write_reg64(t0, ror64(t1, t2 & 63));
             break;
 #endif
 #if TCG_TARGET_HAS_deposit_i64
commit 50c5c4d12557ede48c573e5138542061acd83500
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Mar 18 07:45:39 2014 -0700

    tcg: Mask shift quantities while folding
    
    The TCG result would be undefined, but we can at least produce one
    plausible result and avoid triggering the wrath of analysis tools.
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/optimize.c b/tcg/optimize.c
index 7777743..2fb708e 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -220,34 +220,34 @@ static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
         return x ^ y;
 
     case INDEX_op_shl_i32:
-        return (uint32_t)x << (uint32_t)y;
+        return (uint32_t)x << (y & 31);
 
     case INDEX_op_shl_i64:
-        return (uint64_t)x << (uint64_t)y;
+        return (uint64_t)x << (y & 63);
 
     case INDEX_op_shr_i32:
-        return (uint32_t)x >> (uint32_t)y;
+        return (uint32_t)x >> (y & 31);
 
     case INDEX_op_shr_i64:
-        return (uint64_t)x >> (uint64_t)y;
+        return (uint64_t)x >> (y & 63);
 
     case INDEX_op_sar_i32:
-        return (int32_t)x >> (int32_t)y;
+        return (int32_t)x >> (y & 31);
 
     case INDEX_op_sar_i64:
-        return (int64_t)x >> (int64_t)y;
+        return (int64_t)x >> (y & 63);
 
     case INDEX_op_rotr_i32:
-        return ror32(x, y);
+        return ror32(x, y & 31);
 
     case INDEX_op_rotr_i64:
-        return ror64(x, y);
+        return ror64(x, y & 63);
 
     case INDEX_op_rotl_i32:
-        return rol32(x, y);
+        return rol32(x, y & 31);
 
     case INDEX_op_rotl_i64:
-        return rol64(x, y);
+        return rol64(x, y & 63);
 
     CASE_OP_32_64(not):
         return ~x;
@@ -806,29 +806,34 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
 
         case INDEX_op_sar_i32:
             if (temps[args[2]].state == TCG_TEMP_CONST) {
-                mask = (int32_t)temps[args[1]].mask >> temps[args[2]].val;
+                tmp = temps[args[2]].val & 31;
+                mask = (int32_t)temps[args[1]].mask >> tmp;
             }
             break;
         case INDEX_op_sar_i64:
             if (temps[args[2]].state == TCG_TEMP_CONST) {
-                mask = (int64_t)temps[args[1]].mask >> temps[args[2]].val;
+                tmp = temps[args[2]].val & 63;
+                mask = (int64_t)temps[args[1]].mask >> tmp;
             }
             break;
 
         case INDEX_op_shr_i32:
             if (temps[args[2]].state == TCG_TEMP_CONST) {
-                mask = (uint32_t)temps[args[1]].mask >> temps[args[2]].val;
+                tmp = temps[args[2]].val & 31;
+                mask = (uint32_t)temps[args[1]].mask >> tmp;
             }
             break;
         case INDEX_op_shr_i64:
             if (temps[args[2]].state == TCG_TEMP_CONST) {
-                mask = (uint64_t)temps[args[1]].mask >> temps[args[2]].val;
+                tmp = temps[args[2]].val & 63;
+                mask = (uint64_t)temps[args[1]].mask >> tmp;
             }
             break;
 
         CASE_OP_32_64(shl):
             if (temps[args[2]].state == TCG_TEMP_CONST) {
-                mask = temps[args[1]].mask << temps[args[2]].val;
+                tmp = temps[args[2]].val & (TCG_TARGET_REG_BITS - 1);
+                mask = temps[args[1]].mask << tmp;
             }
             break;
 
commit 20022fa15f6a8ddc24a8f9d7d177312fecc7fb3a
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Mar 18 08:21:44 2014 -0700

    tcg: Use "unspecified behavior" for shifts
    
    Change the definition such that shifts are not allowed to crash
    for any input.
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/README b/tcg/README
index f178212..776e925 100644
--- a/tcg/README
+++ b/tcg/README
@@ -36,6 +36,12 @@ or a memory location which is stored in a register outside QEMU TBs
 A TCG "basic block" corresponds to a list of instructions terminated
 by a branch instruction. 
 
+An operation with "undefined behavior" may result in a crash.
+
+An operation with "unspecified behavior" shall not crash.  However,
+the result may be one of several possibilities so may be considered
+an "undefined result".
+
 3) Intermediate representation
 
 3.1) Introduction
@@ -239,23 +245,25 @@ t0=t1|~t2
 
 * shl_i32/i64 t0, t1, t2
 
-t0=t1 << t2. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+t0=t1 << t2. Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64)
 
 * shr_i32/i64 t0, t1, t2
 
-t0=t1 >> t2 (unsigned). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+t0=t1 >> t2 (unsigned). Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64)
 
 * sar_i32/i64 t0, t1, t2
 
-t0=t1 >> t2 (signed). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+t0=t1 >> t2 (signed). Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64)
 
 * rotl_i32/i64 t0, t1, t2
 
-Rotation of t2 bits to the left. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+Rotation of t2 bits to the left.
+Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64)
 
 * rotr_i32/i64 t0, t1, t2
 
-Rotation of t2 bits to the right. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+Rotation of t2 bits to the right.
+Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64)
 
 ********* Misc
 
commit ad5171dbd419ffa9e10de766e1c3198f2ae62dfa
Author: Stefan Weil <sw at weilnetz.de>
Date:   Fri Feb 21 18:18:34 2014 +0100

    tcg: Fix warning (1 bit signed bitfield entry) and replace int by bool
    
    Static code analyzers complain about signed bitfields with only a single
    bit. is_ld is used as a boolean value, so make it bool.
    
    ppc64 already used bool for the 2nd argument is_ld of the local function
    add_qemu_ldst_label. Modify all other TCG targets to do follow this
    example.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c
index 73ed658..d5500ff 100644
--- a/tcg/aarch64/tcg-target.c
+++ b/tcg/aarch64/tcg-target.c
@@ -1053,7 +1053,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     tcg_out_goto(s, (intptr_t)lb->raddr);
 }
 
-static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOp opc,
+static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc,
                                 TCGReg data_reg, TCGReg addr_reg,
                                 int mem_index,
                                 uint8_t *raddr, uint8_t *label_ptr)
@@ -1226,7 +1226,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
 
     tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 1);
     tcg_out_qemu_ld_direct(s, memop, data_reg, addr_reg, TCG_REG_X1);
-    add_qemu_ldst_label(s, 1, memop, data_reg, addr_reg,
+    add_qemu_ldst_label(s, true, memop, data_reg, addr_reg,
                         mem_index, s->code_ptr, label_ptr);
 #else /* !CONFIG_SOFTMMU */
     tcg_out_qemu_ld_direct(s, memop, data_reg, addr_reg,
@@ -1243,7 +1243,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
 
     tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 0);
     tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg, TCG_REG_X1);
-    add_qemu_ldst_label(s, 0, memop, data_reg, addr_reg,
+    add_qemu_ldst_label(s, false, memop, data_reg, addr_reg,
                         mem_index, s->code_ptr, label_ptr);
 #else /* !CONFIG_SOFTMMU */
     tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg,
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index a65fc65..5a09226 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -1253,7 +1253,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
 /* Record the context of a call to the out of line helper code for the slow
    path for a load or store, so that we can later generate the correct
    helper code.  */
-static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOp opc,
+static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc,
                                 TCGReg datalo, TCGReg datahi, TCGReg addrlo,
                                 TCGReg addrhi, int mem_index,
                                 uint8_t *raddr, uint8_t *label_ptr)
@@ -1519,7 +1519,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
 
     tcg_out_qemu_ld_index(s, opc, datalo, datahi, addrlo, addend);
 
-    add_qemu_ldst_label(s, 1, opc, datalo, datahi, addrlo, addrhi,
+    add_qemu_ldst_label(s, true, opc, datalo, datahi, addrlo, addrhi,
                         mem_index, s->code_ptr, label_ptr);
 #else /* !CONFIG_SOFTMMU */
     if (GUEST_BASE) {
@@ -1647,7 +1647,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
     label_ptr = s->code_ptr;
     tcg_out_bl_noaddr(s, COND_NE);
 
-    add_qemu_ldst_label(s, 0, opc, datalo, datahi, addrlo, addrhi,
+    add_qemu_ldst_label(s, false, opc, datalo, datahi, addrlo, addrhi,
                         mem_index, s->code_ptr, label_ptr);
 #else /* !CONFIG_SOFTMMU */
     if (GUEST_BASE) {
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index f832282..0c2347c 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -1244,7 +1244,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
  * Record the context of a call to the out of line helper code for the slow path
  * for a load or store, so that we can later generate the correct helper code
  */
-static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOp opc,
+static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc,
                                 TCGReg datalo, TCGReg datahi,
                                 TCGReg addrlo, TCGReg addrhi,
                                 int mem_index, uint8_t *raddr,
@@ -1554,7 +1554,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
     tcg_out_qemu_ld_direct(s, datalo, datahi, TCG_REG_L1, 0, 0, opc);
 
     /* Record the current context of a load into ldst label */
-    add_qemu_ldst_label(s, 1, opc, datalo, datahi, addrlo, addrhi,
+    add_qemu_ldst_label(s, true, opc, datalo, datahi, addrlo, addrhi,
                         mem_index, s->code_ptr, label_ptr);
 #else
     {
@@ -1685,7 +1685,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
     tcg_out_qemu_st_direct(s, datalo, datahi, TCG_REG_L1, 0, 0, opc);
 
     /* Record the current context of a store into ldst label */
-    add_qemu_ldst_label(s, 0, opc, datalo, datahi, addrlo, addrhi,
+    add_qemu_ldst_label(s, false, opc, datalo, datahi, addrlo, addrhi,
                         mem_index, s->code_ptr, label_ptr);
 #else
     {
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index dc2c2df..06bedd9 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -524,7 +524,7 @@ static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg,
 #if defined(CONFIG_SOFTMMU)
 
 static void add_qemu_ldst_label (TCGContext *s,
-                                 int is_ld,
+                                 bool is_ld,
                                  TCGMemOp opc,
                                  int data_reg,
                                  int data_reg2,
@@ -720,7 +720,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
         break;
     }
 #ifdef CONFIG_SOFTMMU
-    add_qemu_ldst_label(s, 1, opc, datalo, datahi, addrlo,
+    add_qemu_ldst_label(s, true, opc, datalo, datahi, addrlo,
                         addrhi, mem_index, s->code_ptr, label_ptr);
 #endif
 }
@@ -779,7 +779,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
     }
 
 #ifdef CONFIG_SOFTMMU
-    add_qemu_ldst_label(s, 0, opc, datalo, datahi, addrlo, addrhi,
+    add_qemu_ldst_label(s, false, opc, datalo, datahi, addrlo, addrhi,
                         mem_index, s->code_ptr, label_ptr);
 #endif
 }
diff --git a/tcg/tcg-be-ldst.h b/tcg/tcg-be-ldst.h
index 284db0c..ad94c0c 100644
--- a/tcg/tcg-be-ldst.h
+++ b/tcg/tcg-be-ldst.h
@@ -24,7 +24,7 @@
 #define TCG_MAX_QEMU_LDST       640
 
 typedef struct TCGLabelQemuLdst {
-    int is_ld:1;            /* qemu_ld: 1, qemu_st: 0 */
+    bool is_ld:1;           /* qemu_ld: true, qemu_st: false */
     TCGMemOp opc:4;
     TCGReg addrlo_reg;      /* reg index for low word of guest virtual addr */
     TCGReg addrhi_reg;      /* reg index for high word of guest virtual addr */
commit b36dc67b95dedcece8757ec23bf42625a7ccda34
Author: Stefan Weil <sw at weilnetz.de>
Date:   Mon Apr 7 19:42:59 2014 +0200

    Fix grammar in comment
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index 86f35c1..72c09cb 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -71,7 +71,7 @@ static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int l
     printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
            dev->i2c.address, cmd, buf[0]);
 #endif
-    /* An page write operation is not a valid SMBus command.
+    /* A page write operation is not a valid SMBus command.
        It is a block write without a length byte.  Fortunately we
        get the full block anyway.  */
     /* TODO: Should this set the current location?  */
commit 9d85d557326df69fe0570e7de84b2f57e133c7e7
Author: Michael Tokarev <mjt at tls.msk.ru>
Date:   Mon Apr 7 13:34:58 2014 +0400

    doc: grammify "allows to"
    
    English language grammar does not allow usage
    of the word "allows" directly followed by an
    infinitive, declaring constructs like "something
    allows to do somestuff" un-grammatical.  Often
    it is possible to just insert "one" between "allows"
    and "to" to make the construct grammatical, but
    usually it is better to re-phrase the statement.
    
    This patch tries to fix 4 examples of "allows to"
    usage in qemu doc, but does not address comments
    in the code with similar constructs.  It also adds
    missing "the" in the same line.
    
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/qemu-doc.texi b/qemu-doc.texi
index e6e20eb..88ec9bb 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -823,7 +823,7 @@ In this case, the block device must be exported using qemu-nbd:
 qemu-nbd --socket=/tmp/my_socket my_disk.qcow2
 @end example
 
-The use of qemu-nbd allows to share a disk between several guests:
+The use of qemu-nbd allows sharing of a disk between several guests:
 @example
 qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
 @end example
diff --git a/qemu-options.hx b/qemu-options.hx
index 2d33815..6457034 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -444,7 +444,8 @@ This option defines the type of the media: disk or cdrom.
 @item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
 These options have the same definition as they have in @option{-hdachs}.
 @item snapshot=@var{snapshot}
- at var{snapshot} is "on" or "off" and allows to enable snapshot for given drive (see @option{-snapshot}).
+ at var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
+(see @option{-snapshot}).
 @item cache=@var{cache}
 @var{cache} is "none", "writeback", "unsafe", "directsync" or "writethrough" and controls how the host cache is used to access block data.
 @item aio=@var{aio}
@@ -1242,7 +1243,7 @@ Disable adaptive encodings. Adaptive encodings are enabled by default.
 An adaptive encoding will try to detect frequently updated screen regions,
 and send updates in these regions using a lossy encoding (like JPEG).
 This can be really helpful to save bandwidth when playing videos. Disabling
-adaptive encodings allows to restore the original static behavior of encodings
+adaptive encodings restores the original static behavior of encodings
 like Tight.
 
 @item share=[allow-exclusive|force-shared|ignore]
@@ -2805,7 +2806,7 @@ UTC or local time, respectively. @code{localtime} is required for correct date i
 MS-DOS or Windows. To start at a specific point in time, provide @var{date} in the
 format @code{2006-06-17T16:01:21} or @code{2006-06-17}. The default base is UTC.
 
-By default the RTC is driven by the host system time. This allows to use the
+By default the RTC is driven by the host system time. This allows using of the
 RTC as accurate reference clock inside the guest, specifically if the host
 time is smoothly following an accurate external reference clock, e.g. via NTP.
 If you want to isolate the guest time from the host, you can set @option{clock}
commit 2300aed15d704de102b5577cd0a125bb59d2030a
Author: Stefan Weil <sw at weilnetz.de>
Date:   Fri Mar 14 21:11:13 2014 +0100

    configure: Remove redundant message for -Werror
    
    The compiler flag -Werror is printed (or not printed) as any other
    compiler flag which is part of QEMU_CFLAGS.
    
    Therefore an extra output line for -Werror is redundant and can be removed.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/configure b/configure
index f073072..b08afc3 100755
--- a/configure
+++ b/configure
@@ -4095,7 +4095,6 @@ echo "sparse enabled    $sparse"
 echo "strip binaries    $strip_opt"
 echo "profiler          $profiler"
 echo "static build      $static"
-echo "-Werror enabled   $werror"
 if test "$darwin" = "yes" ; then
     echo "Cocoa support     $cocoa"
 fi
commit e40cdb0e6efb795e4d19368987d53e3e4ae19cf7
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Mar 26 12:45:49 2014 +0100

    scripts: add sample model file for Coverity Scan
    
    This is the model file that is being used for the QEMU project's scans
    on scan.coverity.com.  It fixed about 30 false positives (10% of the
    total) and exposed about 60 new memory leaks.
    
    The file is not automatically used; changes to it must be propagated
    to the website manually by an admin (right now Markus, Peter and me
    are admins).
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/scripts/coverity-model.c b/scripts/coverity-model.c
new file mode 100644
index 0000000..4c99a85
--- /dev/null
+++ b/scripts/coverity-model.c
@@ -0,0 +1,183 @@
+/* Coverity Scan model
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <armbru at redhat.com>
+ *  Paolo Bonzini <pbonzini at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or, at your
+ * option, any later version.  See the COPYING file in the top-level directory.
+ */
+
+
+/*
+ * This is the source code for our Coverity user model file.  The
+ * purpose of user models is to increase scanning accuracy by explaining
+ * code Coverity can't see (out of tree libraries) or doesn't
+ * sufficiently understand.  Better accuracy means both fewer false
+ * positives and more true defects.  Memory leaks in particular.
+ *
+ * - A model file can't import any header files.  Some built-in primitives are
+ *   available but not wchar_t, NULL etc.
+ * - Modeling doesn't need full structs and typedefs. Rudimentary structs
+ *   and similar types are sufficient.
+ * - An uninitialized local variable signifies that the variable could be
+ *   any value.
+ *
+ * The model file must be uploaded by an admin in the analysis settings of
+ * http://scan.coverity.com/projects/378
+ */
+
+#define NULL ((void *)0)
+
+typedef unsigned char uint8_t;
+typedef char int8_t;
+typedef unsigned int uint32_t;
+typedef int int32_t;
+typedef long ssize_t;
+typedef unsigned long long uint64_t;
+typedef long long int64_t;
+typedef _Bool bool;
+
+/* exec.c */
+
+typedef struct AddressSpace AddressSpace;
+typedef uint64_t hwaddr;
+
+static void __write(uint8_t *buf, ssize_t len)
+{
+    int first, last;
+    __coverity_negative_sink__(len);
+    if (len == 0) return;
+    buf[0] = first;
+    buf[len-1] = last;
+    __coverity_writeall__(buf);
+}
+
+static void __read(uint8_t *buf, ssize_t len)
+{
+    __coverity_negative_sink__(len);
+    if (len == 0) return;
+    int first = buf[0];
+    int last = buf[len-1];
+}
+
+bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
+                      int len, bool is_write)
+{
+    bool result;
+
+    // TODO: investigate impact of treating reads as producing
+    // tainted data, with __coverity_tainted_data_argument__(buf).
+    if (is_write) __write(buf, len); else __read(buf, len);
+
+    return result;
+}
+
+/* Tainting */
+
+typedef struct {} name2keysym_t;
+static int get_keysym(const name2keysym_t *table,
+                      const char *name)
+{
+    int result;
+    if (result > 0) {
+        __coverity_tainted_string_sanitize_content__(name);
+        return result;
+    } else {
+        return 0;
+    }
+}
+
+/* glib memory allocation functions.
+ *
+ * Note that we ignore the fact that g_malloc of 0 bytes returns NULL,
+ * and g_realloc of 0 bytes frees the pointer.
+ *
+ * Modeling this would result in Coverity flagging a lot of memory
+ * allocations as potentially returning NULL, and asking us to check
+ * whether the result of the allocation is NULL or not.  However, the
+ * resulting pointer should never be dereferenced anyway, and in fact
+ * it is not in the vast majority of cases.
+ *
+ * If a dereference did happen, this would suppress a defect report
+ * for an actual null pointer dereference.  But it's too unlikely to
+ * be worth wading through the false positives, and with some luck
+ * we'll get a buffer overflow reported anyway.
+ */
+
+void *malloc(size_t);
+void *calloc(size_t, size_t);
+void *realloc(void *, size_t);
+void free(void *);
+
+void *
+g_malloc(size_t n_bytes)
+{
+    void *mem;
+    __coverity_negative_sink__(n_bytes);
+    mem = malloc(n_bytes == 0 ? 1 : n_bytes);
+    if (!mem) __coverity_panic__();
+    return mem;
+}
+
+void *
+g_malloc0(size_t n_bytes)
+{
+    void *mem;
+    __coverity_negative_sink__(n_bytes);
+    mem = calloc(1, n_bytes == 0 ? 1 : n_bytes);
+    if (!mem) __coverity_panic__();
+    return mem;
+}
+
+void g_free(void *mem)
+{
+    free(mem);
+}
+
+void *g_realloc(void * mem, size_t n_bytes)
+{
+    __coverity_negative_sink__(n_bytes);
+    mem = realloc(mem, n_bytes == 0 ? 1 : n_bytes);
+    if (!mem) __coverity_panic__();
+    return mem;
+}
+
+void *g_try_malloc(size_t n_bytes)
+{
+    __coverity_negative_sink__(n_bytes);
+    return malloc(n_bytes == 0 ? 1 : n_bytes);
+}
+
+void *g_try_malloc0(size_t n_bytes)
+{
+    __coverity_negative_sink__(n_bytes);
+    return calloc(1, n_bytes == 0 ? 1 : n_bytes);
+}
+
+void *g_try_realloc(void *mem, size_t n_bytes)
+{
+    __coverity_negative_sink__(n_bytes);
+    return realloc(mem, n_bytes == 0 ? 1 : n_bytes);
+}
+
+/* Other glib functions */
+
+typedef struct _GIOChannel GIOChannel;
+GIOChannel *g_io_channel_unix_new(int fd)
+{
+    GIOChannel *c = g_malloc0(sizeof(GIOChannel));
+    __coverity_escape__(fd);
+    return c;
+}
+
+void g_assertion_message_expr(const char     *domain,
+                              const char     *file,
+                              int             line,
+                              const char     *func,
+                              const char     *expr)
+{
+    __coverity_panic__();
+}
commit 968fc24d843c9e9b24231ca1960b47ef2fc724ea
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Mar 28 15:12:57 2014 +0000

    xbzrle.c: Avoid undefined behaviour with signed arithmetic
    
    Use unsigned types for doing bitwise arithmetic in the xzbrle
    calculations, to avoid undefined behaviour:
    
     xbzrle.c:99:49: runtime error: left shift of 72340172838076673
     by 7 places cannot be represented in type 'long'
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/xbzrle.c b/xbzrle.c
index fbcb35d..8e220bf 100644
--- a/xbzrle.c
+++ b/xbzrle.c
@@ -28,7 +28,7 @@ int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
 {
     uint32_t zrun_len = 0, nzrun_len = 0;
     int d = 0, i = 0;
-    long res, xor;
+    long res;
     uint8_t *nzrun_start = NULL;
 
     g_assert(!(((uintptr_t)old_buf | (uintptr_t)new_buf | slen) %
@@ -93,9 +93,11 @@ int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
         /* word at a time for speed, use of 32-bit long okay */
         if (!res) {
             /* truncation to 32-bit long okay */
-            long mask = (long)0x0101010101010101ULL;
+            unsigned long mask = (unsigned long)0x0101010101010101ULL;
             while (i < slen) {
-                xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i);
+                unsigned long xor;
+                xor = *(unsigned long *)(old_buf + i)
+                    ^ *(unsigned long *)(new_buf + i);
                 if ((xor - mask) & ~xor & (mask << 7)) {
                     /* found the end of an nzrun within the current long */
                     while (old_buf[i] != new_buf[i]) {
commit 423d00c857ebc814ef6b5fc63f1d6c595cdc005d
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Mar 28 15:12:56 2014 +0000

    int128.h: Avoid undefined behaviours involving signed arithmetic
    
    Add casts when we're performing arithmetic on the .hi parts of an
    Int128, to avoid undefined behaviour.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/include/qemu/int128.h b/include/qemu/int128.h
index 9ed47aa..f597031 100644
--- a/include/qemu/int128.h
+++ b/include/qemu/int128.h
@@ -53,7 +53,7 @@ static inline Int128 int128_rshift(Int128 a, int n)
     if (n >= 64) {
         return (Int128) { h, h >> 63 };
     } else {
-        return (Int128) { (a.lo >> n) | (a.hi << (64 - n)), h };
+        return (Int128) { (a.lo >> n) | ((uint64_t)a.hi << (64 - n)), h };
     }
 }
 
@@ -78,7 +78,7 @@ static inline Int128 int128_neg(Int128 a)
 
 static inline Int128 int128_sub(Int128 a, Int128 b)
 {
-    return (Int128){ a.lo - b.lo, a.hi - b.hi - (a.lo < b.lo) };
+    return (Int128){ a.lo - b.lo, (uint64_t)a.hi - b.hi - (a.lo < b.lo) };
 }
 
 static inline bool int128_nonneg(Int128 a)
commit ee25595f0126de0f83da86cc29ba2365be7a50d2
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Mar 28 15:12:55 2014 +0000

    hw/ide/ahci.c: Avoid shift left into sign bit
    
    Add U suffix to avoid shifting left into the sign bit, which
    is undefined behaviour.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index bfe633f..50327ff 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -438,9 +438,9 @@ static void check_cmd(AHCIState *s, int port)
 
     if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
         for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
-            if ((pr->cmd_issue & (1 << slot)) &&
+            if ((pr->cmd_issue & (1U << slot)) &&
                 !handle_cmd(s, port, slot)) {
-                pr->cmd_issue &= ~(1 << slot);
+                pr->cmd_issue &= ~(1U << slot);
             }
         }
     }
commit 86e117724a463b865accfd31eed383c2652c3d17
Author: Hani Benhabiles <kroosec at gmail.com>
Date:   Tue Apr 1 00:05:14 2014 +0100

    net: Report error when device / hub combo is not found.
    
    Also convert nearby monitor_printf() call to error_report().
    
    Signed-off-by: Hani Benhabiles <hani at linux.com>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/net/net.c b/net/net.c
index e3ef1e4..a4aadff 100644
--- a/net/net.c
+++ b/net/net.c
@@ -952,10 +952,12 @@ void net_host_device_remove(Monitor *mon, const QDict *qdict)
 
     nc = net_hub_find_client_by_name(vlan_id, device);
     if (!nc) {
+        error_report("Host network device '%s' on hub '%d' not found",
+                     device, vlan_id);
         return;
     }
     if (!net_host_check_device(nc->model)) {
-        monitor_printf(mon, "invalid host network device %s\n", device);
+        error_report("invalid host network device '%s'", device);
         return;
     }
     qemu_del_net_client(nc);
commit d61ce900b968829666336843df957b86815c08ab
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Mon Mar 31 19:51:55 2014 +0100

    configure: Fix indentation of help for --enable/disable-debug-info
    
    The help text for the --enable-debug-info and --disable-debug-info
    command line options was misindented: delete the stray extra space
    and bring it in to line with everything else.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/configure b/configure
index 69b9f56..f073072 100755
--- a/configure
+++ b/configure
@@ -1217,8 +1217,8 @@ Advanced options (experts only):
   --enable-modules         enable modules support
   --enable-debug-tcg       enable TCG debugging
   --disable-debug-tcg      disable TCG debugging (default)
-  --enable-debug-info       enable debugging information (default)
-  --disable-debug-info      disable debugging information
+  --enable-debug-info      enable debugging information (default)
+  --disable-debug-info     disable debugging information
   --enable-debug           enable common debug build options
   --enable-sparse          enable sparse checker
   --disable-sparse         disable sparse checker (default)
commit 1634df567d1997099bc9abd9312c8c77f09293da
Author: Amos Kong <akong at redhat.com>
Date:   Fri Apr 4 23:25:02 2014 +0800

    qga: trivial fix for unclear documentation of guest-set-time
    
    We mixed the use of "guest time", "system time", "hardware time",
    "RTC" in documentation, it's unclear.
    
    This patch just added two remarks of RTC and replace two "guest time"
    by "guest's system time".
    
    Signed-off-by: Amos Kong <akong at redhat.com>
    Reviewed-by: Michal Privoznik <mprivozn at redhat.com>
    Reviewed-by: Eric Blake <eblake at redhat.com>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 6b5f11f..935a4ec 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -171,7 +171,7 @@ void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
     /* Now, if user has passed a time to set and the system time is set, we
      * just need to synchronize the hardware clock. However, if no time was
      * passed, user is requesting the opposite: set the system time from the
-     * hardware clock. */
+     * hardware clock (RTC). */
     pid = fork();
     if (pid == 0) {
         setsid();
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 80edca1..a8cdcb3 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -96,8 +96,8 @@
 ##
 # @guest-get-time:
 #
-# Get the information about guest time relative to the Epoch
-# of 1970-01-01 in UTC.
+# Get the information about guest's System Time relative to
+# the Epoch of 1970-01-01 in UTC.
 #
 # Returns: Time in nanoseconds.
 #
@@ -117,11 +117,11 @@
 # gap was, NTP might not be able to resynchronize the
 # guest.
 #
-# This command tries to set guest time to the given value,
-# then sets the Hardware Clock to the current System Time.
-# This will make it easier for a guest to resynchronize
-# without waiting for NTP. If no @time is specified, then
-# the time to set is read from RTC.
+# This command tries to set guest's System Time to the
+# given value, then sets the Hardware Clock (RTC) to the
+# current System Time. This will make it easier for a guest
+# to resynchronize without waiting for NTP. If no @time is
+# specified, then the time to set is read from RTC.
 #
 # @time: #optional time of nanoseconds, relative to the Epoch
 #        of 1970-01-01 in UTC.
commit b321afbefd2279a8c93b31a2b13f202c017b974c
Author: Chen Gang <gang.chen.5i5j at gmail.com>
Date:   Fri Apr 4 17:39:33 2014 +0800

    vl: Report accelerator not supported for target more nicely
    
    When you ask for an accelerator not supported for your target, you get
    a bogus "accelerator does not exist" message:
    
      $ qemu-system-arm -machine none,accel=kvm
      KVM not supported for this target
      "kvm" accelerator does not exist.
      No accelerator found!
    
    Suppress it.
    
    Signed-off-by: Chen Gang <gang.chen.5i5j at gmail.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>

diff --git a/vl.c b/vl.c
index 9975e5a..db9ea90 100644
--- a/vl.c
+++ b/vl.c
@@ -2740,7 +2740,7 @@ static int configure_accelerator(QEMUMachine *machine)
                 if (!accel_list[i].available()) {
                     printf("%s not supported for this target\n",
                            accel_list[i].name);
-                    continue;
+                    break;
                 }
                 *(accel_list[i].allowed) = true;
                 ret = accel_list[i].init(machine);
commit 0374f5089ac94d7c58f3f55201b70e8578b35c64
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Mar 4 09:35:30 2014 -0800

    tcg-ia64: Convert to new ldst opcodes
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 76abb46..afcfd36 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -1723,20 +1723,20 @@ static void tcg_out_tb_finalize(TCGContext *s)
     }
 }
 
-static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
-                                   TCGMemOp opc)
+static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args)
 {
     static const uint64_t opc_ld_m1[4] = {
         OPC_LD1_M1, OPC_LD2_M1, OPC_LD4_M1, OPC_LD8_M1
     };
     int addr_reg, data_reg, mem_index;
-    TCGMemOp s_bits;
+    TCGMemOp opc, s_bits;
     uint64_t fin1, fin2;
     uint8_t *label_ptr;
 
-    data_reg = *args++;
-    addr_reg = *args++;
-    mem_index = *args;
+    data_reg = args[0];
+    addr_reg = args[1];
+    opc = args[2];
+    mem_index = args[3];
     s_bits = opc & MO_SIZE;
 
     /* Read the TLB entry */
@@ -1783,8 +1783,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
                    fin2 ? fin2 : INSN_NOP_I);
 }
 
-static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
-                                   TCGMemOp opc)
+static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args)
 {
     static const uint64_t opc_st_m4[4] = {
         OPC_ST1_M4, OPC_ST2_M4, OPC_ST4_M4, OPC_ST8_M4
@@ -1792,12 +1791,13 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
     TCGReg addr_reg, data_reg;
     int mem_index;
     uint64_t pre1, pre2;
-    TCGMemOp s_bits;
+    TCGMemOp opc, s_bits;
     uint8_t *label_ptr;
 
-    data_reg = *args++;
-    addr_reg = *args++;
-    mem_index = *args;
+    data_reg = args[0];
+    addr_reg = args[1];
+    opc = args[2];
+    mem_index = args[3];
     s_bits = opc & MO_SIZE;
 
     /* Note that we always use LE helper functions, so the bswap insns
@@ -1841,17 +1841,17 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
 #else /* !CONFIG_SOFTMMU */
 # include "tcg-be-null.h"
 
-static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
-                                   TCGMemOp opc)
+static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args)
 {
     static uint64_t const opc_ld_m1[4] = {
         OPC_LD1_M1, OPC_LD2_M1, OPC_LD4_M1, OPC_LD8_M1
     };
     int addr_reg, data_reg;
-    TCGMemOp s_bits, bswap;
+    TCGMemOp opc, s_bits, bswap;
 
-    data_reg = *args++;
-    addr_reg = *args++;
+    data_reg = args[0];
+    addr_reg = args[1];
+    opc = args[2];
     s_bits = opc & MO_SIZE;
     bswap = opc & MO_BSWAP;
 
@@ -1962,8 +1962,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
 #endif
 }
 
-static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
-                                   TCGMemOp opc)
+static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args)
 {
     static uint64_t const opc_st_m4[4] = {
         OPC_ST1_M4, OPC_ST2_M4, OPC_ST4_M4, OPC_ST8_M4
@@ -1972,10 +1971,11 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
 #if TARGET_LONG_BITS == 64
     uint64_t add_guest_base;
 #endif
-    TCGMemOp s_bits, bswap;
+    TCGMemOp opc, s_bits, bswap;
 
-    data_reg = *args++;
-    addr_reg = *args++;
+    data_reg = args[0];
+    addr_reg = args[1];
+    opc = args[2];
     s_bits = opc & MO_SIZE;
     bswap = opc & MO_BSWAP;
 
@@ -2299,40 +2299,17 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
                         args[3], const_args[3], args[4], const_args[4], 0);
         break;
 
-    case INDEX_op_qemu_ld8u:
-        tcg_out_qemu_ld(s, args, MO_UB);
+    case INDEX_op_qemu_ld_i32:
+        tcg_out_qemu_ld(s, args);
         break;
-    case INDEX_op_qemu_ld8s:
-        tcg_out_qemu_ld(s, args, MO_SB);
+    case INDEX_op_qemu_ld_i64:
+        tcg_out_qemu_ld(s, args);
         break;
-    case INDEX_op_qemu_ld16u:
-        tcg_out_qemu_ld(s, args, MO_TEUW);
+    case INDEX_op_qemu_st_i32:
+        tcg_out_qemu_st(s, args);
         break;
-    case INDEX_op_qemu_ld16s:
-        tcg_out_qemu_ld(s, args, MO_TESW);
-        break;
-    case INDEX_op_qemu_ld32:
-    case INDEX_op_qemu_ld32u:
-        tcg_out_qemu_ld(s, args, MO_TEUL);
-        break;
-    case INDEX_op_qemu_ld32s:
-        tcg_out_qemu_ld(s, args, MO_TESL);
-        break;
-    case INDEX_op_qemu_ld64:
-        tcg_out_qemu_ld(s, args, MO_TEQ);
-        break;
-
-    case INDEX_op_qemu_st8:
-        tcg_out_qemu_st(s, args, MO_UB);
-        break;
-    case INDEX_op_qemu_st16:
-        tcg_out_qemu_st(s, args, MO_TEUW);
-        break;
-    case INDEX_op_qemu_st32:
-        tcg_out_qemu_st(s, args, MO_TEUL);
-        break;
-    case INDEX_op_qemu_st64:
-        tcg_out_qemu_st(s, args, MO_TEQ);
+    case INDEX_op_qemu_st_i64:
+        tcg_out_qemu_st(s, args);
         break;
 
     default:
@@ -2443,19 +2420,10 @@ static const TCGTargetOpDef ia64_op_defs[] = {
     { INDEX_op_deposit_i32, { "r", "rZ", "ri" } },
     { INDEX_op_deposit_i64, { "r", "rZ", "ri" } },
 
-    { INDEX_op_qemu_ld8u, { "r", "r" } },
-    { INDEX_op_qemu_ld8s, { "r", "r" } },
-    { INDEX_op_qemu_ld16u, { "r", "r" } },
-    { INDEX_op_qemu_ld16s, { "r", "r" } },
-    { INDEX_op_qemu_ld32, { "r", "r" } },
-    { INDEX_op_qemu_ld32u, { "r", "r" } },
-    { INDEX_op_qemu_ld32s, { "r", "r" } },
-    { INDEX_op_qemu_ld64, { "r", "r" } },
-
-    { INDEX_op_qemu_st8, { "SZ", "r" } },
-    { INDEX_op_qemu_st16, { "SZ", "r" } },
-    { INDEX_op_qemu_st32, { "SZ", "r" } },
-    { INDEX_op_qemu_st64, { "SZ", "r" } },
+    { INDEX_op_qemu_ld_i32, { "r", "r" } },
+    { INDEX_op_qemu_ld_i64, { "r", "r" } },
+    { INDEX_op_qemu_st_i32, { "SZ", "r" } },
+    { INDEX_op_qemu_st_i64, { "SZ", "r" } },
 
     { -1 },
 };
diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h
index 52a939c..09c3ba8 100644
--- a/tcg/ia64/tcg-target.h
+++ b/tcg/ia64/tcg-target.h
@@ -153,7 +153,7 @@ typedef enum {
 #define TCG_TARGET_HAS_mulsh_i32        0
 #define TCG_TARGET_HAS_mulsh_i64        0
 
-#define TCG_TARGET_HAS_new_ldst         0
+#define TCG_TARGET_HAS_new_ldst         1
 
 #define TCG_TARGET_deposit_i32_valid(ofs, len) ((len) <= 16)
 #define TCG_TARGET_deposit_i64_valid(ofs, len) ((len) <= 16)
commit 3bf16cb31a32bb4fdd505851f5a71500812ac3de
Author: Richard Henderson <rth at twiddle.net>
Date:   Fri Sep 6 02:06:59 2013 -0400

    tcg-ia64: Move part of softmmu slow path out of line
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 3000a6b..76abb46 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -23,8 +23,6 @@
  * THE SOFTWARE.
  */
 
-#include "tcg-be-null.h"
-
 /*
  * Register definitions
  */
@@ -221,6 +219,7 @@ enum {
     OPC_ALLOC_M34             = 0x02c00000000ull,
     OPC_BR_DPTK_FEW_B1        = 0x08400000000ull,
     OPC_BR_SPTK_MANY_B1       = 0x08000001000ull,
+    OPC_BR_CALL_SPNT_FEW_B3   = 0x0a200000000ull,
     OPC_BR_SPTK_MANY_B4       = 0x00100001000ull,
     OPC_BR_CALL_SPTK_MANY_B5  = 0x02100001000ull,
     OPC_BR_RET_SPTK_MANY_B4   = 0x00108001100ull,
@@ -357,6 +356,15 @@ static inline uint64_t tcg_opc_b1(int qp, uint64_t opc, uint64_t imm)
            | (qp & 0x3f);
 }
 
+static inline uint64_t tcg_opc_b3(int qp, uint64_t opc, int b1, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x100000) << 16) /* s */
+           | ((imm & 0x0fffff) << 13) /* imm20b */
+           | ((b1 & 0x7) << 6)
+           | (qp & 0x3f);
+}
+
 static inline uint64_t tcg_opc_b4(int qp, uint64_t opc, int b2)
 {
     return opc
@@ -1633,14 +1641,87 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg,
                    bswap2);
 }
 
-/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
-   int mmu_idx, uintptr_t retaddr) */
-static const void * const qemu_ld_helpers[4] = {
-    helper_ret_ldub_mmu,
-    helper_le_lduw_mmu,
-    helper_le_ldul_mmu,
-    helper_le_ldq_mmu,
-};
+#define TCG_MAX_QEMU_LDST       640
+
+typedef struct TCGLabelQemuLdst {
+    bool is_ld;
+    TCGMemOp size;
+    uint8_t *label_ptr;     /* label pointers to be updated */
+} TCGLabelQemuLdst;
+
+typedef struct TCGBackendData {
+    int nb_ldst_labels;
+    TCGLabelQemuLdst ldst_labels[TCG_MAX_QEMU_LDST];
+} TCGBackendData;
+
+static inline void tcg_out_tb_init(TCGContext *s)
+{
+    s->be->nb_ldst_labels = 0;
+}
+
+static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc,
+                                uint8_t *label_ptr)
+{
+    TCGBackendData *be = s->be;
+    TCGLabelQemuLdst *l = &be->ldst_labels[be->nb_ldst_labels++];
+
+    assert(be->nb_ldst_labels <= TCG_MAX_QEMU_LDST);
+    l->is_ld = is_ld;
+    l->size = opc & MO_SIZE;
+    l->label_ptr = label_ptr;
+}
+
+static void tcg_out_tb_finalize(TCGContext *s)
+{
+    static const void * const helpers[8] = {
+        helper_ret_stb_mmu,
+        helper_le_stw_mmu,
+        helper_le_stl_mmu,
+        helper_le_stq_mmu,
+        helper_ret_ldub_mmu,
+        helper_le_lduw_mmu,
+        helper_le_ldul_mmu,
+        helper_le_ldq_mmu,
+    };
+    uintptr_t thunks[8] = { };
+    TCGBackendData *be = s->be;
+    size_t i, n = be->nb_ldst_labels;
+
+    for (i = 0; i < n; i++) {
+        TCGLabelQemuLdst *l = &be->ldst_labels[i];
+        long x = l->is_ld * 4 + l->size;
+        uintptr_t dest = thunks[x];
+
+        /* The out-of-line thunks are all the same; load the return address
+           from B0, load the GP, and branch to the code.  Note that we are
+           always post-call, so the register window has rolled, so we're
+           using incomming parameter register numbers, not outgoing.  */
+        if (dest == 0) {
+            uintptr_t disp, *desc = (uintptr_t *)helpers[x];
+
+            thunks[x] = dest = (uintptr_t)s->code_ptr;
+
+            tcg_out_bundle(s, mlx,
+                           INSN_NOP_M,
+                           tcg_opc_l2 (desc[1]),
+                           tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2,
+                                       TCG_REG_R1, desc[1]));
+            tcg_out_bundle(s, mii,
+                           INSN_NOP_M,
+                           INSN_NOP_I,
+                           tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
+                                       l->is_ld ? TCG_REG_R35 : TCG_REG_R36,
+                                       TCG_REG_B0));
+            disp = (desc[0] - (uintptr_t)s->code_ptr) >> 4;
+            tcg_out_bundle(s, mLX,
+                           INSN_NOP_M,
+                           tcg_opc_l3 (disp),
+                           tcg_opc_x3 (TCG_REG_P0, OPC_BRL_SPTK_MANY_X3, disp));
+        }
+
+        reloc_pcrel21b(l->label_ptr, dest);
+    }
+}
 
 static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
                                    TCGMemOp opc)
@@ -1650,7 +1731,8 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
     };
     int addr_reg, data_reg, mem_index;
     TCGMemOp s_bits;
-    uint64_t fin1, fin2, *desc, func, gp, here;
+    uint64_t fin1, fin2;
+    uint8_t *label_ptr;
 
     data_reg = *args++;
     addr_reg = *args++;
@@ -1678,31 +1760,20 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
         fin1 = tcg_opc_ext_i(TCG_REG_P0, opc, data_reg, TCG_REG_R8);
     }
 
-    desc = (uintptr_t *)qemu_ld_helpers[s_bits];
-    func = desc[0];
-    gp = desc[1];
-    here = (uintptr_t)s->code_ptr;
-
-    tcg_out_bundle(s, mlx,
+    tcg_out_bundle(s, mmI,
                    tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R56, TCG_AREG0),
-                   tcg_opc_l2 (here),
-                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R59, here));
-    tcg_out_bundle(s, mLX,
                    tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R2,
                                TCG_REG_R2, TCG_REG_R57),
-                   tcg_opc_l2 (gp),
-                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R1, gp));
-    tcg_out_bundle(s, mmi,
+                   tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R58, mem_index));
+    label_ptr = s->code_ptr + 2;
+    tcg_out_bundle(s, miB,
                    tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
                                TCG_REG_R8, TCG_REG_R2),
-                   tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R58, mem_index),
-                   INSN_NOP_I);
-    func -= (uintptr_t)s->code_ptr;
-    tcg_out_bundle(s, mLX,
-                   INSN_NOP_M,
-                   tcg_opc_l4 (func >> 4),
-                   tcg_opc_x4 (TCG_REG_P7, OPC_BRL_CALL_SPNT_MANY_X4,
-                               TCG_REG_B0, func >> 4));
+                   INSN_NOP_I,
+                   tcg_opc_b3 (TCG_REG_P7, OPC_BR_CALL_SPNT_FEW_B3, TCG_REG_B0,
+                               get_reloc_pcrel21b(label_ptr)));
+
+    add_qemu_ldst_label(s, 1, opc, label_ptr);
 
     /* Note that we always use LE helper functions, so the bswap insns
        here for the fast path also apply to the slow path.  */
@@ -1712,15 +1783,6 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
                    fin2 ? fin2 : INSN_NOP_I);
 }
 
-/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
-   uintxx_t val, int mmu_idx, uintptr_t retaddr) */
-static const void * const qemu_st_helpers[4] = {
-    helper_ret_stb_mmu,
-    helper_le_stw_mmu,
-    helper_le_stl_mmu,
-    helper_le_stq_mmu,
-};
-
 static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
                                    TCGMemOp opc)
 {
@@ -1729,8 +1791,9 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
     };
     TCGReg addr_reg, data_reg;
     int mem_index;
-    uint64_t pre1, pre2, *desc, func, gp, here;
+    uint64_t pre1, pre2;
     TCGMemOp s_bits;
+    uint8_t *label_ptr;
 
     data_reg = *args++;
     addr_reg = *args++;
@@ -1759,35 +1822,24 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
                      pre1, pre2);
 
     /* P6 is the fast path, and P7 the slow path */
-
-    desc = (uintptr_t *)qemu_st_helpers[s_bits];
-    func = desc[0];
-    gp = desc[1];
-    here = (uintptr_t)s->code_ptr;
-
-    tcg_out_bundle(s, mlx,
+    tcg_out_bundle(s, mmI,
                    tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R56, TCG_AREG0),
-                   tcg_opc_l2 (here),
-                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R60, here));
-    tcg_out_bundle(s, mLX,
                    tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R2,
                                TCG_REG_R2, TCG_REG_R57),
-                   tcg_opc_l2 (gp),
-                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R1, gp));
-    tcg_out_bundle(s, mmi,
+                   tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R59, mem_index));
+    label_ptr = s->code_ptr + 2;
+    tcg_out_bundle(s, miB,
                    tcg_opc_m4 (TCG_REG_P6, opc_st_m4[s_bits],
                                TCG_REG_R58, TCG_REG_R2),
-                   tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R59, mem_index),
-                   INSN_NOP_I);
-    func -= (uintptr_t)s->code_ptr;
-    tcg_out_bundle(s, mLX,
-                   INSN_NOP_M,
-                   tcg_opc_l4 (func >> 4),
-                   tcg_opc_x4 (TCG_REG_P7, OPC_BRL_CALL_SPNT_MANY_X4,
-                               TCG_REG_B0, func >> 4));
+                   INSN_NOP_I,
+                   tcg_opc_b3 (TCG_REG_P7, OPC_BR_CALL_SPNT_FEW_B3, TCG_REG_B0,
+                               get_reloc_pcrel21b(label_ptr)));
+
+    add_qemu_ldst_label(s, 0, opc, label_ptr);
 }
 
 #else /* !CONFIG_SOFTMMU */
+# include "tcg-be-null.h"
 
 static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
                                    TCGMemOp opc)
commit 4bdd547aaacd10b7e8f9bf6efe5531ae2ac8ea52
Author: Richard Henderson <rth at twiddle.net>
Date:   Fri Sep 6 00:38:52 2013 -0400

    tcg-ia64: Convert to new ldst helpers
    
    Still inline, but updated to the new routines.  Always use the LE
    helpers, reusing the bswap between the fast and slot paths.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 8464ad6..3000a6b 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -225,6 +225,7 @@ enum {
     OPC_BR_CALL_SPTK_MANY_B5  = 0x02100001000ull,
     OPC_BR_RET_SPTK_MANY_B4   = 0x00108001100ull,
     OPC_BRL_SPTK_MANY_X3      = 0x18000001000ull,
+    OPC_BRL_CALL_SPNT_MANY_X4 = 0x1a200001000ull,
     OPC_BRL_CALL_SPTK_MANY_X4 = 0x1a000001000ull,
     OPC_CMP_LT_A6             = 0x18000000000ull,
     OPC_CMP_LTU_A6            = 0x1a000000000ull,
@@ -815,6 +816,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 #if defined(CONFIG_SOFTMMU)
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_R56);
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_R57);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R58);
 #endif
         break;
     case 'Z':
@@ -1632,12 +1634,12 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg,
 }
 
 /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
-   int mmu_idx) */
+   int mmu_idx, uintptr_t retaddr) */
 static const void * const qemu_ld_helpers[4] = {
-    helper_ldb_mmu,
-    helper_ldw_mmu,
-    helper_ldl_mmu,
-    helper_ldq_mmu,
+    helper_ret_ldub_mmu,
+    helper_le_lduw_mmu,
+    helper_le_ldul_mmu,
+    helper_le_ldq_mmu,
 };
 
 static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
@@ -1648,7 +1650,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
     };
     int addr_reg, data_reg, mem_index;
     TCGMemOp s_bits;
-    uint64_t bswap1, bswap2;
+    uint64_t fin1, fin2, *desc, func, gp, here;
 
     data_reg = *args++;
     addr_reg = *args++;
@@ -1663,52 +1665,60 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
 
     /* P6 is the fast path, and P7 the slow path */
 
-    bswap1 = bswap2 = INSN_NOP_I;
+    fin2 = 0;
     if (opc & MO_BSWAP) {
-        bswap1 = tcg_opc_bswap64_i(TCG_REG_P6, TCG_REG_R8, TCG_REG_R8);
+        fin1 = tcg_opc_bswap64_i(TCG_REG_P0, data_reg, TCG_REG_R8);
         if (s_bits < MO_64) {
             int shift = 64 - (8 << s_bits);
-            bswap2 = (opc & MO_SIGN ? OPC_EXTR_I11 : OPC_EXTR_U_I11);
-            bswap2 = tcg_opc_i11(TCG_REG_P6, bswap2,
-                                 TCG_REG_R8, TCG_REG_R8, shift, 63 - shift);
+            fin2 = (opc & MO_SIGN ? OPC_EXTR_I11 : OPC_EXTR_U_I11);
+            fin2 = tcg_opc_i11(TCG_REG_P0, fin2,
+                               data_reg, data_reg, shift, 63 - shift);
         }
+    } else {
+        fin1 = tcg_opc_ext_i(TCG_REG_P0, opc, data_reg, TCG_REG_R8);
     }
 
-    tcg_out_bundle(s, mLX,
+    desc = (uintptr_t *)qemu_ld_helpers[s_bits];
+    func = desc[0];
+    gp = desc[1];
+    here = (uintptr_t)s->code_ptr;
+
+    tcg_out_bundle(s, mlx,
                    tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R56, TCG_AREG0),
-                   tcg_opc_l2 ((tcg_target_long) qemu_ld_helpers[s_bits]),
-                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2,
-                               (tcg_target_long) qemu_ld_helpers[s_bits]));
-    tcg_out_bundle(s, MmI,
-                   tcg_opc_m3 (TCG_REG_P7, OPC_LD8_M3, TCG_REG_R3,
-                               TCG_REG_R2, 8),
+                   tcg_opc_l2 (here),
+                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R59, here));
+    tcg_out_bundle(s, mLX,
                    tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R2,
                                TCG_REG_R2, TCG_REG_R57),
-                   tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
-                               TCG_REG_R3, 0));
-    tcg_out_bundle(s, MmI,
+                   tcg_opc_l2 (gp),
+                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R1, gp));
+    tcg_out_bundle(s, mmi,
                    tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
                                TCG_REG_R8, TCG_REG_R2),
-                   tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
-                   bswap1);
-    tcg_out_bundle(s, miB,
                    tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R58, mem_index),
-                   bswap2,
-                   tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
-                               TCG_REG_B0, TCG_REG_B6));
-    tcg_out_bundle(s, miI,
+                   INSN_NOP_I);
+    func -= (uintptr_t)s->code_ptr;
+    tcg_out_bundle(s, mLX,
                    INSN_NOP_M,
-                   INSN_NOP_I,
-                   tcg_opc_ext_i(TCG_REG_P0, opc, data_reg, TCG_REG_R8));
+                   tcg_opc_l4 (func >> 4),
+                   tcg_opc_x4 (TCG_REG_P7, OPC_BRL_CALL_SPNT_MANY_X4,
+                               TCG_REG_B0, func >> 4));
+
+    /* Note that we always use LE helper functions, so the bswap insns
+       here for the fast path also apply to the slow path.  */
+    tcg_out_bundle(s, (fin2 ? mII : miI),
+                   INSN_NOP_M,
+                   fin1,
+                   fin2 ? fin2 : INSN_NOP_I);
 }
 
 /* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
-   uintxx_t val, int mmu_idx) */
+   uintxx_t val, int mmu_idx, uintptr_t retaddr) */
 static const void * const qemu_st_helpers[4] = {
-    helper_stb_mmu,
-    helper_stw_mmu,
-    helper_stl_mmu,
-    helper_stq_mmu,
+    helper_ret_stb_mmu,
+    helper_le_stw_mmu,
+    helper_le_stl_mmu,
+    helper_le_stq_mmu,
 };
 
 static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
@@ -1717,56 +1727,64 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
     static const uint64_t opc_st_m4[4] = {
         OPC_ST1_M4, OPC_ST2_M4, OPC_ST4_M4, OPC_ST8_M4
     };
-    TCGReg addr_reg, data_reg, store_reg;
+    TCGReg addr_reg, data_reg;
     int mem_index;
-    uint64_t bswap1, bswap2;
+    uint64_t pre1, pre2, *desc, func, gp, here;
     TCGMemOp s_bits;
 
-    store_reg = data_reg = *args++;
+    data_reg = *args++;
     addr_reg = *args++;
     mem_index = *args;
     s_bits = opc & MO_SIZE;
 
-    bswap1 = bswap2 = INSN_NOP_I;
+    /* Note that we always use LE helper functions, so the bswap insns
+       that are here for the fast path also apply to the slow path,
+       and move the data into the argument register.  */
+    pre2 = INSN_NOP_I;
     if (opc & MO_BSWAP) {
-        store_reg = TCG_REG_R56;
-        bswap1 = tcg_opc_bswap64_i(TCG_REG_P0, store_reg, data_reg);
+        pre1 = tcg_opc_bswap64_i(TCG_REG_P0, TCG_REG_R58, data_reg);
         if (s_bits < MO_64) {
             int shift = 64 - (8 << s_bits);
-            bswap2 = tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11,
-                                 store_reg, store_reg, shift, 63 - shift);
+            pre2 = tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11,
+                               TCG_REG_R58, TCG_REG_R58, shift, 63 - shift);
         }
+    } else {
+        /* Just move the data into place for the slow path.  */
+        pre1 = tcg_opc_ext_i(TCG_REG_P0, opc, TCG_REG_R58, data_reg);
     }
 
     tcg_out_qemu_tlb(s, addr_reg, s_bits,
                      offsetof(CPUArchState, tlb_table[mem_index][0].addr_write),
                      offsetof(CPUArchState, tlb_table[mem_index][0].addend),
-                     bswap1, bswap2);
+                     pre1, pre2);
 
     /* P6 is the fast path, and P7 the slow path */
-    tcg_out_bundle(s, mLX,
+
+    desc = (uintptr_t *)qemu_st_helpers[s_bits];
+    func = desc[0];
+    gp = desc[1];
+    here = (uintptr_t)s->code_ptr;
+
+    tcg_out_bundle(s, mlx,
                    tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R56, TCG_AREG0),
-                   tcg_opc_l2 ((tcg_target_long) qemu_st_helpers[s_bits]),
-                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2,
-                               (tcg_target_long) qemu_st_helpers[s_bits]));
-    tcg_out_bundle(s, MmI,
-                   tcg_opc_m3 (TCG_REG_P7, OPC_LD8_M3, TCG_REG_R3,
-                               TCG_REG_R2, 8),
+                   tcg_opc_l2 (here),
+                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R60, here));
+    tcg_out_bundle(s, mLX,
                    tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R2,
                                TCG_REG_R2, TCG_REG_R57),
-                   tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
-                               TCG_REG_R3, 0));
-    tcg_out_bundle(s, mii,
-                   tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
-                               TCG_REG_R1, TCG_REG_R2),
-                   tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R58, data_reg),
-                   INSN_NOP_I);
-    tcg_out_bundle(s, miB,
+                   tcg_opc_l2 (gp),
+                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R1, gp));
+    tcg_out_bundle(s, mmi,
                    tcg_opc_m4 (TCG_REG_P6, opc_st_m4[s_bits],
-                               store_reg, TCG_REG_R2),
+                               TCG_REG_R58, TCG_REG_R2),
                    tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R59, mem_index),
-                   tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
-                               TCG_REG_B0, TCG_REG_B6));
+                   INSN_NOP_I);
+    func -= (uintptr_t)s->code_ptr;
+    tcg_out_bundle(s, mLX,
+                   INSN_NOP_M,
+                   tcg_opc_l4 (func >> 4),
+                   tcg_opc_x4 (TCG_REG_P7, OPC_BRL_CALL_SPNT_MANY_X4,
+                               TCG_REG_B0, func >> 4));
 }
 
 #else /* !CONFIG_SOFTMMU */
commit af9fe310702396333f983f17de68db8511de7b19
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Sep 5 20:50:54 2013 -0400

    tcg-ia64: Reduce code duplication in tcg_out_qemu_ld
    
    The only differences were in the bswap insns emitted.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 802ec33..8464ad6 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -1647,13 +1647,13 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
         OPC_LD1_M1, OPC_LD2_M1, OPC_LD4_M1, OPC_LD8_M1
     };
     int addr_reg, data_reg, mem_index;
-    TCGMemOp s_bits, bswap;
+    TCGMemOp s_bits;
+    uint64_t bswap1, bswap2;
 
     data_reg = *args++;
     addr_reg = *args++;
     mem_index = *args;
     s_bits = opc & MO_SIZE;
-    bswap = opc & MO_BSWAP;
 
     /* Read the TLB entry */
     tcg_out_qemu_tlb(s, addr_reg, s_bits,
@@ -1662,6 +1662,18 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
                      INSN_NOP_I, INSN_NOP_I);
 
     /* P6 is the fast path, and P7 the slow path */
+
+    bswap1 = bswap2 = INSN_NOP_I;
+    if (opc & MO_BSWAP) {
+        bswap1 = tcg_opc_bswap64_i(TCG_REG_P6, TCG_REG_R8, TCG_REG_R8);
+        if (s_bits < MO_64) {
+            int shift = 64 - (8 << s_bits);
+            bswap2 = (opc & MO_SIGN ? OPC_EXTR_I11 : OPC_EXTR_U_I11);
+            bswap2 = tcg_opc_i11(TCG_REG_P6, bswap2,
+                                 TCG_REG_R8, TCG_REG_R8, shift, 63 - shift);
+        }
+    }
+
     tcg_out_bundle(s, mLX,
                    tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R56, TCG_AREG0),
                    tcg_opc_l2 ((tcg_target_long) qemu_ld_helpers[s_bits]),
@@ -1674,41 +1686,16 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
                                TCG_REG_R2, TCG_REG_R57),
                    tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
                                TCG_REG_R3, 0));
-    if (bswap && s_bits == MO_16) {
-        tcg_out_bundle(s, MmI,
-                       tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
-                                   TCG_REG_R8, TCG_REG_R2),
-                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
-                       tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
-                                   TCG_REG_R8, TCG_REG_R8, 15, 15));
-    } else if (bswap && s_bits == MO_32) {
-        tcg_out_bundle(s, MmI,
-                       tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
-                                   TCG_REG_R8, TCG_REG_R2),
-                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
-                       tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
-                                   TCG_REG_R8, TCG_REG_R8, 31, 31));
-    } else {
-        tcg_out_bundle(s, mmI,
-                       tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
-                                   TCG_REG_R8, TCG_REG_R2),
-                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
-                       INSN_NOP_I);
-    }
-    if (!bswap) {
-        tcg_out_bundle(s, miB,
-                       tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R58, mem_index),
-                       INSN_NOP_I,
-                       tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
-                                   TCG_REG_B0, TCG_REG_B6));
-    } else {
-        tcg_out_bundle(s, miB,
-                       tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R58, mem_index),
-                       tcg_opc_bswap64_i(TCG_REG_P6, TCG_REG_R8, TCG_REG_R8),
-                       tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
-                                   TCG_REG_B0, TCG_REG_B6));
-    }
-
+    tcg_out_bundle(s, MmI,
+                   tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
+                               TCG_REG_R8, TCG_REG_R2),
+                   tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
+                   bswap1);
+    tcg_out_bundle(s, miB,
+                   tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R58, mem_index),
+                   bswap2,
+                   tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+                               TCG_REG_B0, TCG_REG_B6));
     tcg_out_bundle(s, miI,
                    INSN_NOP_M,
                    INSN_NOP_I,
commit 1f91f3921921870e76a8ee543acc0935b5230821
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Sep 5 20:32:49 2013 -0400

    tcg-ia64: Move tlb addend load into tlb read
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index cdc7487..802ec33 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -1569,7 +1569,7 @@ QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table[NB_MMU_MODES - 1][1])
                   > 0x1fffff)
 
 /* Load and compare a TLB entry, and return the result in (p6, p7).
-   R2 is loaded with the address of the addend TLB entry.
+   R2 is loaded with the addend TLB entry.
    R57 is loaded with the address, zero extented on 32-bit targets.
    R1, R3 are clobbered, leaving R56 free for...
    BSWAP_1, BSWAP_2 and I-slot insns for swapping data for store.  */
@@ -1625,7 +1625,7 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg,
                                TCG_REG_R2, off_add - off_rw),
                    bswap1);
     tcg_out_bundle(s, mmI,
-                   INSN_NOP_M,
+                   tcg_opc_m1 (TCG_REG_P0, OPC_LD8_M1, TCG_REG_R2, TCG_REG_R2),
                    tcg_opc_a6 (TCG_REG_P0, OPC_CMP_EQ_A6, TCG_REG_P6,
                                TCG_REG_P7, TCG_REG_R1, TCG_REG_R3),
                    bswap2);
@@ -1668,30 +1668,30 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
                    tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2,
                                (tcg_target_long) qemu_ld_helpers[s_bits]));
     tcg_out_bundle(s, MmI,
-                   tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3,
+                   tcg_opc_m3 (TCG_REG_P7, OPC_LD8_M3, TCG_REG_R3,
                                TCG_REG_R2, 8),
-                   tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3,
-                               TCG_REG_R3, TCG_REG_R57),
+                   tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R2,
+                               TCG_REG_R2, TCG_REG_R57),
                    tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
                                TCG_REG_R3, 0));
     if (bswap && s_bits == MO_16) {
         tcg_out_bundle(s, MmI,
                        tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
-                                   TCG_REG_R8, TCG_REG_R3),
+                                   TCG_REG_R8, TCG_REG_R2),
                        tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
                        tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
                                    TCG_REG_R8, TCG_REG_R8, 15, 15));
     } else if (bswap && s_bits == MO_32) {
         tcg_out_bundle(s, MmI,
                        tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
-                                   TCG_REG_R8, TCG_REG_R3),
+                                   TCG_REG_R8, TCG_REG_R2),
                        tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
                        tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
                                    TCG_REG_R8, TCG_REG_R8, 31, 31));
     } else {
         tcg_out_bundle(s, mmI,
                        tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
-                                   TCG_REG_R8, TCG_REG_R3),
+                                   TCG_REG_R8, TCG_REG_R2),
                        tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
                        INSN_NOP_I);
     }
@@ -1763,10 +1763,10 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
                    tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2,
                                (tcg_target_long) qemu_st_helpers[s_bits]));
     tcg_out_bundle(s, MmI,
-                   tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3,
+                   tcg_opc_m3 (TCG_REG_P7, OPC_LD8_M3, TCG_REG_R3,
                                TCG_REG_R2, 8),
-                   tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3,
-                               TCG_REG_R3, TCG_REG_R57),
+                   tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R2,
+                               TCG_REG_R2, TCG_REG_R57),
                    tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
                                TCG_REG_R3, 0));
     tcg_out_bundle(s, mii,
@@ -1776,7 +1776,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
                    INSN_NOP_I);
     tcg_out_bundle(s, miB,
                    tcg_opc_m4 (TCG_REG_P6, opc_st_m4[s_bits],
-                               store_reg, TCG_REG_R3),
+                               store_reg, TCG_REG_R2),
                    tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R59, mem_index),
                    tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
                                TCG_REG_B0, TCG_REG_B6));
commit b672cf66c37a5fc9fc143160d2395901030c9d3a
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Sep 5 20:02:51 2013 -0400

    tcg-ia64: Move bswap for store into tlb load
    
    Saving at least two cycles per store, and cleaning up the code.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 7bb3440..cdc7487 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -1571,9 +1571,11 @@ QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table[NB_MMU_MODES - 1][1])
 /* Load and compare a TLB entry, and return the result in (p6, p7).
    R2 is loaded with the address of the addend TLB entry.
    R57 is loaded with the address, zero extented on 32-bit targets.
-   R1, R3 are clobbered. */
+   R1, R3 are clobbered, leaving R56 free for...
+   BSWAP_1, BSWAP_2 and I-slot insns for swapping data for store.  */
 static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg,
-                                    TCGMemOp s_bits, int off_rw, int off_add)
+                                    TCGMemOp s_bits, int off_rw, int off_add,
+                                    uint64_t bswap1, uint64_t bswap2)
 {
      /*
         .mii
@@ -1621,12 +1623,12 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg,
                                (TARGET_LONG_BITS == 32
                                 ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R3,
                                TCG_REG_R2, off_add - off_rw),
-                   INSN_NOP_I);
+                   bswap1);
     tcg_out_bundle(s, mmI,
                    INSN_NOP_M,
                    tcg_opc_a6 (TCG_REG_P0, OPC_CMP_EQ_A6, TCG_REG_P6,
                                TCG_REG_P7, TCG_REG_R1, TCG_REG_R3),
-                   INSN_NOP_I);
+                   bswap2);
 }
 
 /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
@@ -1656,7 +1658,8 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
     /* Read the TLB entry */
     tcg_out_qemu_tlb(s, addr_reg, s_bits,
                      offsetof(CPUArchState, tlb_table[mem_index][0].addr_read),
-                     offsetof(CPUArchState, tlb_table[mem_index][0].addend));
+                     offsetof(CPUArchState, tlb_table[mem_index][0].addend),
+                     INSN_NOP_I, INSN_NOP_I);
 
     /* P6 is the fast path, and P7 the slow path */
     tcg_out_bundle(s, mLX,
@@ -1727,17 +1730,31 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
     static const uint64_t opc_st_m4[4] = {
         OPC_ST1_M4, OPC_ST2_M4, OPC_ST4_M4, OPC_ST8_M4
     };
-    int addr_reg, data_reg, mem_index;
+    TCGReg addr_reg, data_reg, store_reg;
+    int mem_index;
+    uint64_t bswap1, bswap2;
     TCGMemOp s_bits;
 
-    data_reg = *args++;
+    store_reg = data_reg = *args++;
     addr_reg = *args++;
     mem_index = *args;
     s_bits = opc & MO_SIZE;
 
+    bswap1 = bswap2 = INSN_NOP_I;
+    if (opc & MO_BSWAP) {
+        store_reg = TCG_REG_R56;
+        bswap1 = tcg_opc_bswap64_i(TCG_REG_P0, store_reg, data_reg);
+        if (s_bits < MO_64) {
+            int shift = 64 - (8 << s_bits);
+            bswap2 = tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11,
+                                 store_reg, store_reg, shift, 63 - shift);
+        }
+    }
+
     tcg_out_qemu_tlb(s, addr_reg, s_bits,
                      offsetof(CPUArchState, tlb_table[mem_index][0].addr_write),
-                     offsetof(CPUArchState, tlb_table[mem_index][0].addend));
+                     offsetof(CPUArchState, tlb_table[mem_index][0].addend),
+                     bswap1, bswap2);
 
     /* P6 is the fast path, and P7 the slow path */
     tcg_out_bundle(s, mLX,
@@ -1752,63 +1769,14 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
                                TCG_REG_R3, TCG_REG_R57),
                    tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
                                TCG_REG_R3, 0));
-
-    switch (opc) {
-    case MO_8:
-    case MO_16:
-    case MO_32:
-    case MO_64:
-        tcg_out_bundle(s, mii,
-                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
-                                   TCG_REG_R1, TCG_REG_R2),
-                       tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R58, data_reg),
-                       INSN_NOP_I);
-        break;
-
-    case MO_16 | MO_BSWAP:
-        tcg_out_bundle(s, miI,
-                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
-                                   TCG_REG_R1, TCG_REG_R2),
-                       INSN_NOP_I,
-                       tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
-                                   TCG_REG_R2, data_reg, 15, 15));
-        tcg_out_bundle(s, miI,
-                       tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R58, data_reg),
-                       INSN_NOP_I,
-                       tcg_opc_bswap64_i(TCG_REG_P6, TCG_REG_R2, TCG_REG_R2));
-        data_reg = TCG_REG_R2;
-        break;
-
-    case MO_32 | MO_BSWAP:
-        tcg_out_bundle(s, miI,
-                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
-                                   TCG_REG_R1, TCG_REG_R2),
-                       INSN_NOP_I,
-                       tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
-                                   TCG_REG_R2, data_reg, 31, 31));
-        tcg_out_bundle(s, miI,
-                       tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R58, data_reg),
-                       INSN_NOP_I,
-                       tcg_opc_bswap64_i(TCG_REG_P6, TCG_REG_R2, TCG_REG_R2));
-        data_reg = TCG_REG_R2;
-        break;
-
-    case MO_64 | MO_BSWAP:
-        tcg_out_bundle(s, miI,
-                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
-                                   TCG_REG_R1, TCG_REG_R2),
-                       tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R58, data_reg),
-                       tcg_opc_bswap64_i(TCG_REG_P6, TCG_REG_R2, data_reg));
-        data_reg = TCG_REG_R2;
-        break;
-
-    default:
-        tcg_abort();
-    }
-
+    tcg_out_bundle(s, mii,
+                   tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
+                               TCG_REG_R1, TCG_REG_R2),
+                   tcg_opc_mov_a(TCG_REG_P7, TCG_REG_R58, data_reg),
+                   INSN_NOP_I);
     tcg_out_bundle(s, miB,
                    tcg_opc_m4 (TCG_REG_P6, opc_st_m4[s_bits],
-                               data_reg, TCG_REG_R3),
+                               store_reg, TCG_REG_R3),
                    tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R59, mem_index),
                    tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
                                TCG_REG_B0, TCG_REG_B6));
commit 4c186ee2cf938d338a4fc4e53789a59d580b7625
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Sep 5 19:46:56 2013 -0400

    tcg-ia64: Re-bundle the tlb load
    
    This sequencing requires 5 stop bits instead of 6, and has room left
    over to pre-load the tlb addend, and bswap data prior to being stored.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 7407011..7bb3440 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -1564,38 +1564,69 @@ static inline void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGArg ret,
 }
 
 #if defined(CONFIG_SOFTMMU)
+/* We're expecting to use an signed 22-bit immediate add.  */
+QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table[NB_MMU_MODES - 1][1])
+                  > 0x1fffff)
+
 /* Load and compare a TLB entry, and return the result in (p6, p7).
    R2 is loaded with the address of the addend TLB entry.
-   R57 is loaded with the address, zero extented on 32-bit targets. */
-static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg,
-                                    TCGMemOp s_bits, uint64_t offset_rw,
-                                    uint64_t offset_addend)
-{
-    tcg_out_bundle(s, mII,
-                   INSN_NOP_M,
-                   tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, TCG_REG_R2,
+   R57 is loaded with the address, zero extented on 32-bit targets.
+   R1, R3 are clobbered. */
+static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg,
+                                    TCGMemOp s_bits, int off_rw, int off_add)
+{
+     /*
+        .mii
+        mov	r2 = off_rw
+        extr.u	r3 = addr_reg, ...		# extract tlb page
+        zxt4	r57 = addr_reg                  # or mov for 64-bit guest
+        ;;
+        .mii
+        addl	r2 = r2, areg0
+        shl	r3 = r3, cteb                   # via dep.z
+        dep	r1 = 0, r57, ...                # zero page ofs, keep align
+        ;;
+        .mmi
+        add	r2 = r2, r3
+        ;;
+        ld4	r3 = [r2], off_add-off_rw	# or ld8 for 64-bit guest
+        nop
+        ;;
+        .mmi
+        nop
+        cmp.eq	p6, p7 = r3, r58
+        nop
+        ;;
+      */
+    tcg_out_bundle(s, miI,
+                   tcg_opc_movi_a(TCG_REG_P0, TCG_REG_R2, off_rw),
+                   tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, TCG_REG_R3,
                                addr_reg, TARGET_PAGE_BITS, CPU_TLB_BITS - 1),
-                   tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, TCG_REG_R2,
-                               TCG_REG_R2, 63 - CPU_TLB_ENTRY_BITS,
-                               63 - CPU_TLB_ENTRY_BITS));
-    tcg_out_bundle(s, mII,
-                   tcg_opc_a5 (TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R2,
-                               offset_rw, TCG_REG_R2),
                    tcg_opc_ext_i(TCG_REG_P0,
                                  TARGET_LONG_BITS == 32 ? MO_UL : MO_Q,
-                                 TCG_REG_R57, addr_reg),
+                                 TCG_REG_R57, addr_reg));
+    tcg_out_bundle(s, miI,
                    tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
-                               TCG_REG_R2, TCG_AREG0));
-    tcg_out_bundle(s, mII,
+                               TCG_REG_R2, TCG_AREG0),
+                   tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, TCG_REG_R3,
+                               TCG_REG_R3, 63 - CPU_TLB_ENTRY_BITS,
+                               63 - CPU_TLB_ENTRY_BITS),
+                   tcg_opc_i14(TCG_REG_P0, OPC_DEP_I14, TCG_REG_R1, 0,
+                               TCG_REG_R57, 63 - s_bits,
+                               TARGET_PAGE_BITS - s_bits - 1));
+    tcg_out_bundle(s, MmI,
+                   tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1,
+                               TCG_REG_R2, TCG_REG_R2, TCG_REG_R3),
                    tcg_opc_m3 (TCG_REG_P0,
                                (TARGET_LONG_BITS == 32
-                                ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R56,
-                               TCG_REG_R2, offset_addend - offset_rw),
-                   tcg_opc_i14(TCG_REG_P0, OPC_DEP_I14, TCG_REG_R3, 0,
-                               TCG_REG_R57, 63 - s_bits,
-                               TARGET_PAGE_BITS - s_bits - 1),
+                                ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R3,
+                               TCG_REG_R2, off_add - off_rw),
+                   INSN_NOP_I);
+    tcg_out_bundle(s, mmI,
+                   INSN_NOP_M,
                    tcg_opc_a6 (TCG_REG_P0, OPC_CMP_EQ_A6, TCG_REG_P6,
-                               TCG_REG_P7, TCG_REG_R3, TCG_REG_R56));
+                               TCG_REG_P7, TCG_REG_R1, TCG_REG_R3),
+                   INSN_NOP_I);
 }
 
 /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
commit dcf91778caa36338a252703f6d40f06cc14acfce
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Oct 31 15:19:23 2013 -0400

    tcg-ia64: Optimize small arguments to exit_tb
    
    Saves one bundle for the common case of exit_tb 0.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 2d8e00c..7407011 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -950,15 +950,21 @@ static inline void tcg_out_callr(TCGContext *s, TCGReg addr)
 static void tcg_out_exit_tb(TCGContext *s, tcg_target_long arg)
 {
     int64_t disp;
-    uint64_t imm;
+    uint64_t imm, opc1;
 
-    tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R8, arg);
+    /* At least arg == 0 is a common operation.  */
+    if (arg == sextract64(arg, 0, 22)) {
+        opc1 = tcg_opc_movi_a(TCG_REG_P0, TCG_REG_R8, arg);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R8, arg);
+        opc1 = INSN_NOP_M;
+    }
 
     disp = tb_ret_addr - s->code_ptr;
     imm = (uint64_t)disp >> 4;
 
     tcg_out_bundle(s, mLX,
-                   INSN_NOP_M,
+                   opc1,
                    tcg_opc_l3 (imm),
                    tcg_opc_x3 (TCG_REG_P0, OPC_BRL_SPTK_MANY_X3, imm));
 }


More information about the Spice-commits mailing list