aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure3
-rw-r--r--docs/specs/standard-vga.txt13
-rw-r--r--hw/audio/hda-codec.c3
-rw-r--r--hw/display/cirrus_vga.c4
-rw-r--r--hw/display/qxl.c2
-rw-r--r--hw/display/vga-isa-mm.c2
-rw-r--r--hw/display/vga-isa.c2
-rw-r--r--hw/display/vga-pci.c63
-rw-r--r--hw/display/vga.c8
-rw-r--r--hw/display/vga_int.h2
-rw-r--r--hw/display/vmware_vga.c2
-rw-r--r--hw/intc/openpic_kvm.c8
-rw-r--r--hw/intc/xics_kvm.c8
-rw-r--r--include/exec/def-helper.h2
-rw-r--r--include/sysemu/kvm.h30
-rw-r--r--target-ppc/kvm.c21
-rw-r--r--target-s390x/kvm.c4
-rw-r--r--tcg/README5
-rw-r--r--tcg/aarch64/tcg-target.h1
-rw-r--r--tcg/i386/tcg-target.h1
-rw-r--r--tcg/ia64/tcg-target.h1
-rw-r--r--tcg/optimize.c16
-rw-r--r--tcg/ppc64/tcg-target.h1
-rw-r--r--tcg/s390/tcg-target.h1
-rw-r--r--tcg/sparc/tcg-target.c842
-rw-r--r--tcg/sparc/tcg-target.h17
-rw-r--r--tcg/tcg-op.h54
-rw-r--r--tcg/tcg-opc.h4
-rw-r--r--tcg/tcg.c80
-rw-r--r--tcg/tcg.h1
-rw-r--r--tcg/tci/tcg-target.h1
-rw-r--r--tests/Makefile5
-rw-r--r--tests/display-vga-test.c52
-rw-r--r--ui/gtk.c88
-rw-r--r--ui/sdl2.c51
35 files changed, 741 insertions, 657 deletions
diff --git a/configure b/configure
index 2fbec59..870c939 100755
--- a/configure
+++ b/configure
@@ -1233,6 +1233,7 @@ Advanced options (experts only):
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
--disable-gtk disable gtk UI
--enable-gtk enable gtk UI
+ --with-gtkabi select preferred GTK ABI 2.0 or 3.0
--disable-virtfs disable VirtFS
--enable-virtfs enable VirtFS
--disable-vnc disable VNC
@@ -4349,6 +4350,7 @@ if test "$modules" = "yes"; then
fi
if test "$sdl" = "yes" ; then
echo "CONFIG_SDL=y" >> $config_host_mak
+ echo "CONFIG_SDLABI=$sdlabi" >> $config_host_mak
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
fi
if test "$cocoa" = "yes" ; then
@@ -4432,6 +4434,7 @@ fi
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
if test "$gtk" = "yes" ; then
echo "CONFIG_GTK=y" >> $config_host_mak
+ echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
fi
if test "$vte" = "yes" ; then
diff --git a/docs/specs/standard-vga.txt b/docs/specs/standard-vga.txt
index 8a4c1e9..f82773e 100644
--- a/docs/specs/standard-vga.txt
+++ b/docs/specs/standard-vga.txt
@@ -5,9 +5,10 @@ QEMU Standard VGA
Exists in two variants, for isa and pci.
command line switches:
- -vga std [ picks isa for -M isapc, otherwise pci ]
- -device VGA [ pci variant ]
- -device isa-vga [ isa variant ]
+ -vga std [ picks isa for -M isapc, otherwise pci ]
+ -device VGA [ pci variant ]
+ -device isa-vga [ isa variant ]
+ -device secondary-vga [ legacy-free pci variant ]
PCI spec
@@ -31,9 +32,15 @@ PCI ROM Region:
Holds the vgabios (qemu 0.14+).
+The legacy-free variant has no ROM and has PCI_CLASS_DISPLAY_OTHER
+instead of PCI_CLASS_DISPLAY_VGA.
+
+
IO ports used
-------------
+Doesn't apply to the legacy-free pci variant, use the MMIO bar instead.
+
03c0 - 03df : standard vga ports
01ce : bochs vbe interface index port
01cf : bochs vbe interface data port (x86 only)
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index a67ca91..48c6ead 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -261,6 +261,9 @@ static void hda_audio_set_amp(HDAAudioStream *st)
left = left * 255 / QEMU_HDA_AMP_STEPS;
right = right * 255 / QEMU_HDA_AMP_STEPS;
+ if (!st->state->mixer) {
+ return;
+ }
if (st->output) {
AUD_set_volume_out(st->voice.out, muted, left, right);
} else {
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 0d3127d..d1afc76 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -2913,7 +2913,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev);
VGACommonState *s = &d->cirrus_vga.vga;
- vga_common_init(s, OBJECT(dev));
+ vga_common_init(s, OBJECT(dev), true);
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
isa_address_space(isadev),
isa_address_space_io(isadev));
@@ -2960,7 +2960,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
int16_t device_id = pc->device_id;
/* setup VGA */
- vga_common_init(&s->vga, OBJECT(dev));
+ vga_common_init(&s->vga, OBJECT(dev), true);
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
pci_address_space_io(dev));
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 47bbf1f..e9c54d7 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2061,7 +2061,7 @@ static int qxl_init_primary(PCIDevice *dev)
qxl->id = 0;
qxl_init_ramsize(qxl);
vga->vram_size_mb = qxl->vga.vram_size >> 20;
- vga_common_init(vga, OBJECT(dev));
+ vga_common_init(vga, OBJECT(dev), true);
vga_init(vga, OBJECT(dev),
pci_address_space(dev), pci_address_space_io(dev), false);
portio_list_init(qxl_vga_port_list, OBJECT(dev), qxl_vga_portio_list,
diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c
index afc46b8..4efc222 100644
--- a/hw/display/vga-isa-mm.c
+++ b/hw/display/vga-isa-mm.c
@@ -132,7 +132,7 @@ int isa_vga_mm_init(hwaddr vram_base,
s = g_malloc0(sizeof(*s));
s->vga.vram_size_mb = VGA_RAM_SIZE >> 20;
- vga_common_init(&s->vga, NULL);
+ vga_common_init(&s->vga, NULL, true);
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index 1d9ea6b..2b480bd 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -56,7 +56,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
MemoryRegion *vga_io_memory;
const MemoryRegionPortio *vga_ports, *vbe_ports;
- vga_common_init(s, OBJECT(dev));
+ vga_common_init(s, OBJECT(dev), true);
s->legacy_address_space = isa_address_space(isadev);
vga_io_memory = vga_init_io(s, OBJECT(dev), &vga_ports, &vbe_ports);
isa_register_portio_list(isadev, 0x3b0, vga_ports, s, "vga");
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 574ea0e..0865dc4 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -147,7 +147,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
VGACommonState *s = &d->vga;
/* vga + console init */
- vga_common_init(s, OBJECT(dev));
+ vga_common_init(s, OBJECT(dev), true);
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
true);
@@ -179,12 +179,51 @@ static int pci_std_vga_initfn(PCIDevice *dev)
return 0;
}
+static int pci_secondary_vga_initfn(PCIDevice *dev)
+{
+ PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
+ VGACommonState *s = &d->vga;
+
+ /* vga + console init */
+ vga_common_init(s, OBJECT(dev), false);
+ s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
+
+ /* mmio bar */
+ memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio", 4096);
+ memory_region_init_io(&d->ioport, OBJECT(dev), &pci_vga_ioport_ops, d,
+ "vga ioports remapped", PCI_VGA_IOPORT_SIZE);
+ memory_region_init_io(&d->bochs, OBJECT(dev), &pci_vga_bochs_ops, d,
+ "bochs dispi interface", PCI_VGA_BOCHS_SIZE);
+
+ memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET,
+ &d->ioport);
+ memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET,
+ &d->bochs);
+
+ pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+ pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
+
+ return 0;
+}
+
+static void pci_secondary_vga_reset(DeviceState *dev)
+{
+ PCIVGAState *d = DO_UPCAST(PCIVGAState, dev.qdev, dev);
+
+ vga_common_reset(&d->vga);
+}
+
static Property vga_pci_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
DEFINE_PROP_END_OF_LIST(),
};
+static Property secondary_pci_properties[] = {
+ DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void vga_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -201,6 +240,20 @@ static void vga_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
}
+static void secondary_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_secondary_vga_initfn;
+ k->vendor_id = PCI_VENDOR_ID_QEMU;
+ k->device_id = PCI_DEVICE_ID_QEMU_VGA;
+ k->class_id = PCI_CLASS_DISPLAY_OTHER;
+ dc->vmsd = &vmstate_vga_pci;
+ dc->props = secondary_pci_properties;
+ dc->reset = pci_secondary_vga_reset;
+}
+
static const TypeInfo vga_info = {
.name = "VGA",
.parent = TYPE_PCI_DEVICE,
@@ -208,9 +261,17 @@ static const TypeInfo vga_info = {
.class_init = vga_class_init,
};
+static const TypeInfo secondary_info = {
+ .name = "secondary-vga",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIVGAState),
+ .class_init = secondary_class_init,
+};
+
static void vga_register_types(void)
{
type_register_static(&vga_info);
+ type_register_static(&secondary_info);
}
type_init(vga_register_types)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 063319d..c4c3238 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -171,6 +171,10 @@ static void vga_update_memory_access(VGACommonState *s)
MemoryRegion *region, *old_region = s->chain4_alias;
hwaddr base, offset, size;
+ if (s->legacy_address_space == NULL) {
+ return;
+ }
+
s->chain4_alias = NULL;
if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
@@ -2252,7 +2256,7 @@ static const GraphicHwOps vga_ops = {
.text_update = vga_update_text,
};
-void vga_common_init(VGACommonState *s, Object *obj)
+void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
{
int i, j, v, b;
@@ -2289,7 +2293,7 @@ void vga_common_init(VGACommonState *s, Object *obj)
s->is_vbe_vmstate = 1;
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size);
- vmstate_register_ram_global(&s->vram);
+ vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
xen_register_framebuffer(&s->vram);
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
s->get_bpp = vga_get_bpp;
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index e641890..d42ac92 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -177,7 +177,7 @@ static inline int c6_to_8(int v)
return (v << 2) | (b << 1) | b;
}
-void vga_common_init(VGACommonState *s, Object *obj);
+void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate);
void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
MemoryRegion *address_space_io, bool init_vga_ports);
MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 6ae3348..9ba47e6 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1207,7 +1207,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
vmstate_register_ram_global(&s->fifo_ram);
s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
- vga_common_init(&s->vga, OBJECT(dev));
+ vga_common_init(&s->vga, OBJECT(dev), true);
vga_init(&s->vga, OBJECT(dev), address_space, io, true);
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
s->new_depth = 32;
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index 6635407..585ab4f 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -234,13 +234,9 @@ static void kvm_openpic_realize(DeviceState *dev, Error **errp)
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
{
KVMOpenPICState *opp = KVM_OPENPIC(d);
- struct kvm_enable_cap encap = {};
- encap.cap = KVM_CAP_IRQ_MPIC;
- encap.args[0] = opp->fd;
- encap.args[1] = kvm_arch_vcpu_id(cs);
-
- return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
+ return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
+ kvm_arch_vcpu_id(cs));
}
static Property kvm_openpic_properties[] = {
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index c93dae0..09476ae 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -331,15 +331,11 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
if (icpkvm->kernel_xics_fd != -1) {
int ret;
- struct kvm_enable_cap xics_enable_cap = {
- .cap = KVM_CAP_IRQ_XICS,
- .flags = 0,
- .args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0},
- };
ss->cs = cs;
- ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0,
+ icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs));
if (ret < 0) {
error_report("Unable to connect CPU%ld to kernel XICS: %s",
kvm_arch_vcpu_id(cs), strerror(errno));
diff --git a/include/exec/def-helper.h b/include/exec/def-helper.h
index 73d51f9..255b58b 100644
--- a/include/exec/def-helper.h
+++ b/include/exec/def-helper.h
@@ -84,7 +84,7 @@
#define dh_is_64bit_noreturn 0
#define dh_is_64bit_i32 0
#define dh_is_64bit_i64 1
-#define dh_is_64bit_ptr (TCG_TARGET_REG_BITS == 64)
+#define dh_is_64bit_ptr (sizeof(void *) == 8)
#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t))
#define dh_is_signed_void 0
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 0bee1e8..192fe89 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -294,6 +294,36 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cpu);
int kvm_check_extension(KVMState *s, unsigned int extension);
+#define kvm_vm_enable_cap(s, capability, cap_flags, ...) \
+ ({ \
+ struct kvm_enable_cap cap = { \
+ .cap = capability, \
+ .flags = cap_flags, \
+ }; \
+ uint64_t args_tmp[] = { __VA_ARGS__ }; \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(args_tmp) && \
+ i < ARRAY_SIZE(cap.args); i++) { \
+ cap.args[i] = args_tmp[i]; \
+ } \
+ kvm_vm_ioctl(s, KVM_ENABLE_CAP, &cap); \
+ })
+
+#define kvm_vcpu_enable_cap(cpu, capability, cap_flags, ...) \
+ ({ \
+ struct kvm_enable_cap cap = { \
+ .cap = capability, \
+ .flags = cap_flags, \
+ }; \
+ uint64_t args_tmp[] = { __VA_ARGS__ }; \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(args_tmp) && \
+ i < ARRAY_SIZE(cap.args); i++) { \
+ cap.args[i] = args_tmp[i]; \
+ } \
+ kvm_vcpu_ioctl(cpu, KVM_ENABLE_CAP, &cap); \
+ })
+
uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
uint32_t index, int reg);
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 9974b10..4b81e5f 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -151,7 +151,6 @@ static int kvm_booke206_tlb_init(PowerPCCPU *cpu)
CPUState *cs = CPU(cpu);
struct kvm_book3e_206_tlb_params params = {};
struct kvm_config_tlb cfg = {};
- struct kvm_enable_cap encap = {};
unsigned int entries = 0;
int ret, i;
@@ -178,10 +177,7 @@ static int kvm_booke206_tlb_init(PowerPCCPU *cpu)
cfg.params = (uintptr_t)&params;
cfg.mmu_type = KVM_MMU_FSL_BOOKE_NOHV;
- encap.cap = KVM_CAP_SW_TLB;
- encap.args[0] = (uintptr_t)&cfg;
-
- ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_SW_TLB, 0, (uintptr_t)&cfg);
if (ret < 0) {
fprintf(stderr, "%s: couldn't enable KVM_CAP_SW_TLB: %s\n",
__func__, strerror(-ret));
@@ -1292,7 +1288,6 @@ int kvmppc_set_tcr(PowerPCCPU *cpu)
int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
- struct kvm_enable_cap encap = {};
int ret;
if (!kvm_enabled()) {
@@ -1304,8 +1299,7 @@ int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
return -1;
}
- encap.cap = KVM_CAP_PPC_BOOKE_WATCHDOG;
- ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_BOOKE_WATCHDOG, 0);
if (ret < 0) {
fprintf(stderr, "%s: couldn't enable KVM_CAP_PPC_BOOKE_WATCHDOG: %s\n",
__func__, strerror(-ret));
@@ -1505,12 +1499,9 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
void kvmppc_set_papr(PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
- struct kvm_enable_cap cap = {};
int ret;
- cap.cap = KVM_CAP_PPC_PAPR;
- ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap);
-
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_PAPR, 0);
if (ret) {
cpu_abort(cs, "This KVM version does not support PAPR\n");
}
@@ -1523,13 +1514,9 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
{
CPUState *cs = CPU(cpu);
- struct kvm_enable_cap cap = {};
int ret;
- cap.cap = KVM_CAP_PPC_EPR;
- cap.args[0] = mpic_proxy;
- ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap);
-
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_EPR, 0, mpic_proxy);
if (ret && mpic_proxy) {
cpu_abort(cs, "This KVM version does not support EPR\n");
}
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index a30d1bc..b7b0edc 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -929,12 +929,10 @@ void kvm_s390_crw_mchk(S390CPU *cpu)
void kvm_s390_enable_css_support(S390CPU *cpu)
{
- struct kvm_enable_cap cap = {};
int r;
/* Activate host kernel channel subsystem support. */
- cap.cap = KVM_CAP_S390_CSS_SUPPORT;
- r = kvm_vcpu_ioctl(CPU(cpu), KVM_ENABLE_CAP, &cap);
+ r = kvm_vcpu_enable_cap(CPU(cpu), KVM_CAP_S390_CSS_SUPPORT, 0);
assert(r == 0);
}
diff --git a/tcg/README b/tcg/README
index 776e925..a550ff1 100644
--- a/tcg/README
+++ b/tcg/README
@@ -314,6 +314,11 @@ This operation would be equivalent to
dest = (t1 & ~0x0f00) | ((t2 << 8) & 0x0f00)
+* trunc_shr_i32 t0, t1, pos
+
+For 64-bit hosts only, right shift the 64-bit input T1 by POS and
+truncate to 32-bit output T0. Depending on the host, this may be
+a simple mov/shift, or may require additional canonicalization.
********* Conditional moves
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index eff1d68..a1d4322 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -68,6 +68,7 @@ typedef enum {
#define TCG_TARGET_HAS_muls2_i32 0
#define TCG_TARGET_HAS_muluh_i32 0
#define TCG_TARGET_HAS_mulsh_i32 0
+#define TCG_TARGET_HAS_trunc_shr_i32 0
#define TCG_TARGET_HAS_div_i64 1
#define TCG_TARGET_HAS_rem_i64 1
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index ababca0..dbeb16d 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -99,6 +99,7 @@ extern bool have_bmi1;
#define TCG_TARGET_HAS_mulsh_i32 0
#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_trunc_shr_i32 0
#define TCG_TARGET_HAS_div2_i64 1
#define TCG_TARGET_HAS_rot_i64 1
#define TCG_TARGET_HAS_ext8s_i64 1
diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h
index 09c3ba8..d834beb 100644
--- a/tcg/ia64/tcg-target.h
+++ b/tcg/ia64/tcg-target.h
@@ -152,6 +152,7 @@ typedef enum {
#define TCG_TARGET_HAS_muluh_i64 0
#define TCG_TARGET_HAS_mulsh_i32 0
#define TCG_TARGET_HAS_mulsh_i64 0
+#define TCG_TARGET_HAS_trunc_shr_i32 0
#define TCG_TARGET_HAS_new_ldst 1
diff --git a/tcg/optimize.c b/tcg/optimize.c
index c447062..0302f4f 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -228,6 +228,7 @@ static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
case INDEX_op_shr_i32:
return (uint32_t)x >> (y & 31);
+ case INDEX_op_trunc_shr_i32:
case INDEX_op_shr_i64:
return (uint64_t)x >> (y & 63);
@@ -830,6 +831,10 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
}
break;
+ case INDEX_op_trunc_shr_i32:
+ mask = (uint64_t)temps[args[1]].mask >> args[2];
+ break;
+
CASE_OP_32_64(shl):
if (temps[args[2]].state == TCG_TEMP_CONST) {
tmp = temps[args[2]].val & (TCG_TARGET_REG_BITS - 1);
@@ -1021,6 +1026,17 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
}
goto do_default;
+ case INDEX_op_trunc_shr_i32:
+ if (temps[args[1]].state == TCG_TEMP_CONST) {
+ s->gen_opc_buf[op_index] = op_to_movi(op);
+ tmp = do_constant_folding(op, temps[args[1]].val, args[2]);
+ tcg_opt_gen_movi(gen_args, args[0], tmp);
+ gen_args += 2;
+ args += 3;
+ break;
+ }
+ goto do_default;
+
CASE_OP_32_64(add):
CASE_OP_32_64(sub):
CASE_OP_32_64(mul):
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
index 78bbf7a..3815b84 100644
--- a/tcg/ppc64/tcg-target.h
+++ b/tcg/ppc64/tcg-target.h
@@ -96,6 +96,7 @@ typedef enum {
#define TCG_TARGET_HAS_muls2_i32 0
#define TCG_TARGET_HAS_muluh_i32 0
#define TCG_TARGET_HAS_mulsh_i32 0
+#define TCG_TARGET_HAS_trunc_shr_i32 0
#define TCG_TARGET_HAS_div_i64 1
#define TCG_TARGET_HAS_rem_i64 0
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index b3bfdcc..755c002 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -69,6 +69,7 @@ typedef enum TCGReg {
#define TCG_TARGET_HAS_muls2_i32 0
#define TCG_TARGET_HAS_muluh_i32 0
#define TCG_TARGET_HAS_mulsh_i32 0
+#define TCG_TARGET_HAS_trunc_shr_i32 0
#define TCG_TARGET_HAS_div2_i64 1
#define TCG_TARGET_HAS_rot_i64 1
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 35089b8..5468ff5 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -61,6 +61,24 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
};
#endif
+#ifdef __arch64__
+# define SPARC64 1
+#else
+# define SPARC64 0
+#endif
+
+/* Note that sparcv8plus can only hold 64 bit quantities in %g and %o
+ registers. These are saved manually by the kernel in full 64-bit
+ slots. The %i and %l registers are saved by the register window
+ mechanism, which only allocates space for 32 bits. Given that this
+ window spill/fill can happen on any signal, we must consider the
+ high bits of the %i and %l registers garbage at all times. */
+#if SPARC64
+# define ALL_64 0xffffffffu
+#else
+# define ALL_64 0xffffu
+#endif
+
/* Define some temporary registers. T2 is used for constant generation. */
#define TCG_REG_T1 TCG_REG_G1
#define TCG_REG_T2 TCG_REG_O7
@@ -182,6 +200,7 @@ static const int tcg_target_call_oarg_regs[] = {
#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x08))
#define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c))
#define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a))
+#define ARITH_SMUL (INSN_OP(2) | INSN_OP3(0x0b))
#define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e))
#define ARITH_SDIV (INSN_OP(2) | INSN_OP3(0x0f))
#define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09))
@@ -201,6 +220,7 @@ static const int tcg_target_call_oarg_regs[] = {
#define RDY (INSN_OP(2) | INSN_OP3(0x28) | INSN_RS1(0))
#define WRY (INSN_OP(2) | INSN_OP3(0x30) | INSN_RD(0))
#define JMPL (INSN_OP(2) | INSN_OP3(0x38))
+#define RETURN (INSN_OP(2) | INSN_OP3(0x39))
#define SAVE (INSN_OP(2) | INSN_OP3(0x3c))
#define RESTORE (INSN_OP(2) | INSN_OP3(0x3d))
#define SETHI (INSN_OP(0) | INSN_OP2(0x4))
@@ -242,17 +262,23 @@ static const int tcg_target_call_oarg_regs[] = {
#define STW_LE (STWA | INSN_ASI(ASI_PRIMARY_LITTLE))
#define STX_LE (STXA | INSN_ASI(ASI_PRIMARY_LITTLE))
-static inline int check_fit_tl(tcg_target_long val, unsigned int bits)
+static inline int check_fit_i64(int64_t val, unsigned int bits)
{
- return (val << ((sizeof(tcg_target_long) * 8 - bits))
- >> (sizeof(tcg_target_long) * 8 - bits)) == val;
+ return val == sextract64(val, 0, bits);
}
-static inline int check_fit_i32(uint32_t val, unsigned int bits)
+static inline int check_fit_i32(int32_t val, unsigned int bits)
{
- return ((val << (32 - bits)) >> (32 - bits)) == val;
+ return val == sextract32(val, 0, bits);
}
+#define check_fit_tl check_fit_i64
+#if SPARC64
+# define check_fit_ptr check_fit_i64
+#else
+# define check_fit_ptr check_fit_i32
+#endif
+
static void patch_reloc(uint8_t *code_ptr, int type,
intptr_t value, intptr_t addend)
{
@@ -267,7 +293,7 @@ static void patch_reloc(uint8_t *code_ptr, int type,
break;
case R_SPARC_WDISP16:
value -= (intptr_t)code_ptr;
- if (!check_fit_tl(value >> 2, 16)) {
+ if (!check_fit_ptr(value >> 2, 16)) {
tcg_abort();
}
insn = *(uint32_t *)code_ptr;
@@ -277,7 +303,7 @@ static void patch_reloc(uint8_t *code_ptr, int type,
break;
case R_SPARC_WDISP19:
value -= (intptr_t)code_ptr;
- if (!check_fit_tl(value >> 2, 19)) {
+ if (!check_fit_ptr(value >> 2, 19)) {
tcg_abort();
}
insn = *(uint32_t *)code_ptr;
@@ -301,14 +327,27 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
ct->ct |= TCG_CT_REG;
tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
break;
- case 'L': /* qemu_ld/st constraint */
+ case 'R':
ct->ct |= TCG_CT_REG;
- tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
- // Helper args
+ tcg_regset_set32(ct->u.regs, 0, ALL_64);
+ break;
+ case 'A': /* qemu_ld/st address constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0,
+ TARGET_LONG_BITS == 64 ? ALL_64 : 0xffffffff);
+ reserve_helpers:
tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2);
break;
+ case 's': /* qemu_st data 32-bit constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ goto reserve_helpers;
+ case 'S': /* qemu_st data 64-bit constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, ALL_64);
+ goto reserve_helpers;
case 'I':
ct->ct |= TCG_CT_CONST_S11;
break;
@@ -351,22 +390,20 @@ static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
}
}
-static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2,
- int op)
+static inline void tcg_out_arith(TCGContext *s, TCGReg rd, TCGReg rs1,
+ TCGReg rs2, int op)
{
- tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) |
- INSN_RS2(rs2));
+ tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | INSN_RS2(rs2));
}
-static inline void tcg_out_arithi(TCGContext *s, int rd, int rs1,
- uint32_t offset, int op)
+static inline void tcg_out_arithi(TCGContext *s, TCGReg rd, TCGReg rs1,
+ int32_t offset, int op)
{
- tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) |
- INSN_IMM13(offset));
+ tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | INSN_IMM13(offset));
}
-static void tcg_out_arithc(TCGContext *s, int rd, int rs1,
- int val2, int val2const, int op)
+static void tcg_out_arithc(TCGContext *s, TCGReg rd, TCGReg rs1,
+ int32_t val2, int val2const, int op)
{
tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1)
| (val2const ? INSN_IMM13(val2) : INSN_RS2(val2)));
@@ -380,12 +417,12 @@ static inline void tcg_out_mov(TCGContext *s, TCGType type,
}
}
-static inline void tcg_out_sethi(TCGContext *s, int ret, uint32_t arg)
+static inline void tcg_out_sethi(TCGContext *s, TCGReg ret, uint32_t arg)
{
tcg_out32(s, SETHI | INSN_RD(ret) | ((arg & 0xfffffc00) >> 10));
}
-static inline void tcg_out_movi_imm13(TCGContext *s, int ret, uint32_t arg)
+static inline void tcg_out_movi_imm13(TCGContext *s, TCGReg ret, int32_t arg)
{
tcg_out_arithi(s, ret, TCG_REG_G0, arg, ARITH_OR);
}
@@ -393,7 +430,12 @@ static inline void tcg_out_movi_imm13(TCGContext *s, int ret, uint32_t arg)
static void tcg_out_movi(TCGContext *s, TCGType type,
TCGReg ret, tcg_target_long arg)
{
- tcg_target_long hi, lo;
+ tcg_target_long hi, lo = (int32_t)arg;
+
+ /* Make sure we test 32-bit constants for imm13 properly. */
+ if (type == TCG_TYPE_I32) {
+ arg = lo;
+ }
/* A 13-bit constant sign-extended to 64-bits. */
if (check_fit_tl(arg, 13)) {
@@ -402,9 +444,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
}
/* A 32-bit constant, or 32-bit zero-extended to 64-bits. */
- if (TCG_TARGET_REG_BITS == 32
- || type == TCG_TYPE_I32
- || (arg & ~0xffffffffu) == 0) {
+ if (type == TCG_TYPE_I32 || arg == (uint32_t)arg) {
tcg_out_sethi(s, ret, arg);
if (arg & 0x3ff) {
tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR);
@@ -413,21 +453,20 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
}
/* A 32-bit constant sign-extended to 64-bits. */
- if (check_fit_tl(arg, 32)) {
+ if (arg == lo) {
tcg_out_sethi(s, ret, ~arg);
tcg_out_arithi(s, ret, ret, (arg & 0x3ff) | -0x400, ARITH_XOR);
return;
}
/* A 64-bit constant decomposed into 2 32-bit pieces. */
- lo = (int32_t)arg;
- if (check_fit_tl(lo, 13)) {
- hi = (arg - lo) >> 31 >> 1;
+ if (check_fit_i32(lo, 13)) {
+ hi = (arg - lo) >> 32;
tcg_out_movi(s, TCG_TYPE_I32, ret, hi);
tcg_out_arithi(s, ret, ret, 32, SHIFT_SLLX);
tcg_out_arithi(s, ret, ret, lo, ARITH_ADD);
} else {
- hi = arg >> 31 >> 1;
+ hi = arg >> 32;
tcg_out_movi(s, TCG_TYPE_I32, ret, hi);
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T2, lo);
tcg_out_arithi(s, ret, ret, 32, SHIFT_SLLX);
@@ -435,16 +474,16 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
}
}
-static inline void tcg_out_ldst_rr(TCGContext *s, int data, int a1,
- int a2, int op)
+static inline void tcg_out_ldst_rr(TCGContext *s, TCGReg data, TCGReg a1,
+ TCGReg a2, int op)
{
tcg_out32(s, op | INSN_RD(data) | INSN_RS1(a1) | INSN_RS2(a2));
}
-static inline void tcg_out_ldst(TCGContext *s, int ret, int addr,
- int offset, int op)
+static void tcg_out_ldst(TCGContext *s, TCGReg ret, TCGReg addr,
+ intptr_t offset, int op)
{
- if (check_fit_tl(offset, 13)) {
+ if (check_fit_ptr(offset, 13)) {
tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) |
INSN_IMM13(offset));
} else {
@@ -465,40 +504,24 @@ static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
tcg_out_ldst(s, arg, arg1, arg2, (type == TCG_TYPE_I32 ? STW : STX));
}
-static inline void tcg_out_ld_ptr(TCGContext *s, TCGReg ret, uintptr_t arg)
+static void tcg_out_ld_ptr(TCGContext *s, TCGReg ret, uintptr_t arg)
{
- TCGReg base = TCG_REG_G0;
- if (!check_fit_tl(arg, 10)) {
- tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ff);
- base = ret;
- }
- tcg_out_ld(s, TCG_TYPE_PTR, ret, base, arg & 0x3ff);
+ tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ff);
+ tcg_out_ld(s, TCG_TYPE_PTR, ret, ret, arg & 0x3ff);
}
-static inline void tcg_out_sety(TCGContext *s, int rs)
+static inline void tcg_out_sety(TCGContext *s, TCGReg rs)
{
tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs));
}
-static inline void tcg_out_rdy(TCGContext *s, int rd)
+static inline void tcg_out_rdy(TCGContext *s, TCGReg rd)
{
tcg_out32(s, RDY | INSN_RD(rd));
}
-static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
-{
- if (val != 0) {
- if (check_fit_tl(val, 13))
- tcg_out_arithi(s, reg, reg, val, ARITH_ADD);
- else {
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, val);
- tcg_out_arith(s, reg, reg, TCG_REG_T1, ARITH_ADD);
- }
- }
-}
-
-static void tcg_out_div32(TCGContext *s, int rd, int rs1,
- int val2, int val2const, int uns)
+static void tcg_out_div32(TCGContext *s, TCGReg rd, TCGReg rs1,
+ int32_t val2, int val2const, int uns)
{
/* Load Y with the sign/zero extension of RS1 to 64-bits. */
if (uns) {
@@ -559,38 +582,37 @@ static void tcg_out_bpcc(TCGContext *s, int scond, int flags, int label)
tcg_out_bpcc0(s, scond, flags, off19);
}
-static void tcg_out_cmp(TCGContext *s, TCGArg c1, TCGArg c2, int c2const)
+static void tcg_out_cmp(TCGContext *s, TCGReg c1, int32_t c2, int c2const)
{
tcg_out_arithc(s, TCG_REG_G0, c1, c2, c2const, ARITH_SUBCC);
}
-static void tcg_out_brcond_i32(TCGContext *s, TCGCond cond, TCGArg arg1,
- TCGArg arg2, int const_arg2, int label)
+static void tcg_out_brcond_i32(TCGContext *s, TCGCond cond, TCGReg arg1,
+ int32_t arg2, int const_arg2, int label)
{
tcg_out_cmp(s, arg1, arg2, const_arg2);
tcg_out_bpcc(s, tcg_cond_to_bcond[cond], BPCC_ICC | BPCC_PT, label);
tcg_out_nop(s);
}
-static void tcg_out_movcc(TCGContext *s, TCGCond cond, int cc, TCGArg ret,
- TCGArg v1, int v1const)
+static void tcg_out_movcc(TCGContext *s, TCGCond cond, int cc, TCGReg ret,
+ int32_t v1, int v1const)
{
tcg_out32(s, ARITH_MOVCC | cc | INSN_RD(ret)
| INSN_RS1(tcg_cond_to_bcond[cond])
| (v1const ? INSN_IMM11(v1) : INSN_RS2(v1)));
}
-static void tcg_out_movcond_i32(TCGContext *s, TCGCond cond, TCGArg ret,
- TCGArg c1, TCGArg c2, int c2const,
- TCGArg v1, int v1const)
+static void tcg_out_movcond_i32(TCGContext *s, TCGCond cond, TCGReg ret,
+ TCGReg c1, int32_t c2, int c2const,
+ int32_t v1, int v1const)
{
tcg_out_cmp(s, c1, c2, c2const);
tcg_out_movcc(s, cond, MOVCC_ICC, ret, v1, v1const);
}
-#if TCG_TARGET_REG_BITS == 64
-static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond, TCGArg arg1,
- TCGArg arg2, int const_arg2, int label)
+static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond, TCGReg arg1,
+ int32_t arg2, int const_arg2, int label)
{
/* For 64-bit signed comparisons vs zero, we can avoid the compare. */
if (arg2 == 0 && !is_unsigned_cond(cond)) {
@@ -613,71 +635,32 @@ static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond, TCGArg arg1,
tcg_out_nop(s);
}
-static void tcg_out_movr(TCGContext *s, TCGCond cond, TCGArg ret, TCGArg c1,
- TCGArg v1, int v1const)
+static void tcg_out_movr(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg c1,
+ int32_t v1, int v1const)
{
tcg_out32(s, ARITH_MOVR | INSN_RD(ret) | INSN_RS1(c1)
| (tcg_cond_to_rcond[cond] << 10)
| (v1const ? INSN_IMM10(v1) : INSN_RS2(v1)));
}
-static void tcg_out_movcond_i64(TCGContext *s, TCGCond cond, TCGArg ret,
- TCGArg c1, TCGArg c2, int c2const,
- TCGArg v1, int v1const)
+static void tcg_out_movcond_i64(TCGContext *s, TCGCond cond, TCGReg ret,
+ TCGReg c1, int32_t c2, int c2const,
+ int32_t v1, int v1const)
{
/* For 64-bit signed comparisons vs zero, we can avoid the compare.
Note that the immediate range is one bit smaller, so we must check
for that as well. */
if (c2 == 0 && !is_unsigned_cond(cond)
- && (!v1const || check_fit_tl(v1, 10))) {
+ && (!v1const || check_fit_i32(v1, 10))) {
tcg_out_movr(s, cond, ret, c1, v1, v1const);
} else {
tcg_out_cmp(s, c1, c2, c2const);
tcg_out_movcc(s, cond, MOVCC_XCC, ret, v1, v1const);
}
}
-#else
-static void tcg_out_brcond2_i32(TCGContext *s, TCGCond cond,
- TCGArg al, TCGArg ah,
- TCGArg bl, int blconst,
- TCGArg bh, int bhconst, int label_dest)
-{
- int scond, label_next = gen_new_label();
-
- tcg_out_cmp(s, ah, bh, bhconst);
-
- /* Note that we fill one of the delay slots with the second compare. */
- switch (cond) {
- case TCG_COND_EQ:
- tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_next);
- tcg_out_cmp(s, al, bl, blconst);
- tcg_out_bpcc(s, COND_E, BPCC_ICC | BPCC_PT, label_dest);
- break;
-
- case TCG_COND_NE:
- tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_dest);
- tcg_out_cmp(s, al, bl, blconst);
- tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_dest);
- break;
-
- default:
- scond = tcg_cond_to_bcond[tcg_high_cond(cond)];
- tcg_out_bpcc(s, scond, BPCC_ICC | BPCC_PT, label_dest);
- tcg_out_nop(s);
- tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_next);
- tcg_out_cmp(s, al, bl, blconst);
- scond = tcg_cond_to_bcond[tcg_unsigned_cond(cond)];
- tcg_out_bpcc(s, scond, BPCC_ICC | BPCC_PT, label_dest);
- break;
- }
- tcg_out_nop(s);
- tcg_out_label(s, label_next, s->code_ptr);
-}
-#endif
-
-static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret,
- TCGArg c1, TCGArg c2, int c2const)
+static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGReg ret,
+ TCGReg c1, int32_t c2, int c2const)
{
/* For 32-bit comparisons, we can play games with ADDX/SUBX. */
switch (cond) {
@@ -702,7 +685,7 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret,
swap the operands on GTU/LEU. There's no benefit to loading
the constant into a temporary register. */
if (!c2const || c2 == 0) {
- TCGArg t = c1;
+ TCGReg t = c1;
c1 = c2;
c2 = t;
c2const = 0;
@@ -726,9 +709,8 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret,
}
}
-#if TCG_TARGET_REG_BITS == 64
-static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGArg ret,
- TCGArg c1, TCGArg c2, int c2const)
+static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGReg ret,
+ TCGReg c1, int32_t c2, int c2const)
{
/* For 64-bit signed comparisons vs zero, we can avoid the compare
if the input does not overlap the output. */
@@ -741,54 +723,12 @@ static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGArg ret,
tcg_out_movcc(s, cond, MOVCC_XCC, ret, 1, 1);
}
}
-#else
-static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret,
- TCGArg al, TCGArg ah,
- TCGArg bl, int blconst,
- TCGArg bh, int bhconst)
-{
- int tmp = TCG_REG_T1;
-
- /* Note that the low parts are fully consumed before tmp is set. */
- if (ret != ah && (bhconst || ret != bh)) {
- tmp = ret;
- }
-
- switch (cond) {
- case TCG_COND_EQ:
- case TCG_COND_NE:
- if (bl == 0 && bh == 0) {
- if (cond == TCG_COND_EQ) {
- tcg_out_arith(s, TCG_REG_G0, al, ah, ARITH_ORCC);
- tcg_out_movi(s, TCG_TYPE_I32, ret, 1);
- } else {
- tcg_out_arith(s, ret, al, ah, ARITH_ORCC);
- }
- } else {
- tcg_out_setcond_i32(s, cond, tmp, al, bl, blconst);
- tcg_out_cmp(s, ah, bh, bhconst);
- tcg_out_mov(s, TCG_TYPE_I32, ret, tmp);
- }
- tcg_out_movcc(s, TCG_COND_NE, MOVCC_ICC, ret, cond == TCG_COND_NE, 1);
- break;
- default:
- /* <= : ah < bh | (ah == bh && al <= bl) */
- tcg_out_setcond_i32(s, tcg_unsigned_cond(cond), tmp, al, bl, blconst);
- tcg_out_cmp(s, ah, bh, bhconst);
- tcg_out_mov(s, TCG_TYPE_I32, ret, tmp);
- tcg_out_movcc(s, TCG_COND_NE, MOVCC_ICC, ret, 0, 1);
- tcg_out_movcc(s, tcg_high_cond(cond), MOVCC_ICC, ret, 1, 1);
- break;
- }
-}
-#endif
-
-static void tcg_out_addsub2(TCGContext *s, TCGArg rl, TCGArg rh,
- TCGArg al, TCGArg ah, TCGArg bl, int blconst,
- TCGArg bh, int bhconst, int opl, int oph)
+static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh,
+ TCGReg al, TCGReg ah, int32_t bl, int blconst,
+ int32_t bh, int bhconst, int opl, int oph)
{
- TCGArg tmp = TCG_REG_T1;
+ TCGReg tmp = TCG_REG_T1;
/* Note that the low parts are fully consumed before tmp is set. */
if (rl != ah && (bhconst || rl != bh)) {
@@ -800,7 +740,7 @@ static void tcg_out_addsub2(TCGContext *s, TCGArg rl, TCGArg rh,
tcg_out_mov(s, TCG_TYPE_I32, rl, tmp);
}
-static inline void tcg_out_calli(TCGContext *s, uintptr_t dest)
+static void tcg_out_calli(TCGContext *s, uintptr_t dest)
{
intptr_t disp = dest - (uintptr_t)s->code_ptr;
@@ -857,8 +797,13 @@ static void build_trampolines(TCGContext *s)
}
qemu_ld_trampoline[i] = tramp;
- /* Find the retaddr argument register. */
- ra = TCG_REG_O3 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS);
+ if (SPARC64 || TARGET_LONG_BITS == 32) {
+ ra = TCG_REG_O3;
+ } else {
+ /* Install the high part of the address. */
+ tcg_out_arithi(s, TCG_REG_O1, TCG_REG_O2, 32, SHIFT_SRLX);
+ ra = TCG_REG_O4;
+ }
/* Set the retaddr operand. */
tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7);
@@ -882,12 +827,28 @@ static void build_trampolines(TCGContext *s)
}
qemu_st_trampoline[i] = tramp;
- /* Find the retaddr argument. For 32-bit, this may be past the
- last argument register, and need passing on the stack. */
- ra = (TCG_REG_O4
- + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)
- + (TCG_TARGET_REG_BITS == 32 && (i & MO_SIZE) == MO_64));
-
+ if (SPARC64) {
+ ra = TCG_REG_O4;
+ } else {
+ ra = TCG_REG_O1;
+ if (TARGET_LONG_BITS == 64) {
+ /* Install the high part of the address. */
+ tcg_out_arithi(s, ra, ra + 1, 32, SHIFT_SRLX);
+ ra += 2;
+ } else {
+ ra += 1;
+ }
+ if ((i & MO_SIZE) == MO_64) {
+ /* Install the high part of the data. */
+ tcg_out_arithi(s, ra, ra + 1, 32, SHIFT_SRLX);
+ ra += 2;
+ } else {
+ ra += 1;
+ }
+ /* Skip the mem_index argument. */
+ ra += 1;
+ }
+
/* Set the retaddr operand. */
if (ra >= TCG_REG_O6) {
tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_O7, TCG_REG_CALL_STACK,
@@ -956,25 +917,16 @@ static void tcg_target_qemu_prologue(TCGContext *s)
The result of the TLB comparison is in %[ix]cc. The sanitized address
is in the returned register, maybe %o0. The TLB addend is in %o1. */
-static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
- int mem_index, TCGMemOp s_bits, int which)
+static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addr, int mem_index,
+ TCGMemOp s_bits, int which)
{
const TCGReg r0 = TCG_REG_O0;
const TCGReg r1 = TCG_REG_O1;
const TCGReg r2 = TCG_REG_O2;
- TCGReg addr = addrlo;
int tlb_ofs;
- if (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) {
- /* Assemble the 64-bit address in R0. */
- tcg_out_arithi(s, r0, addrlo, 0, SHIFT_SRL);
- tcg_out_arithi(s, r1, addrhi, 32, SHIFT_SLLX);
- tcg_out_arith(s, r0, r0, r1, ARITH_OR);
- addr = r0;
- }
-
/* Shift the page number down. */
- tcg_out_arithi(s, r1, addrlo, TARGET_PAGE_BITS, SHIFT_SRL);
+ tcg_out_arithi(s, r1, addr, TARGET_PAGE_BITS, SHIFT_SRL);
/* Mask out the page offset, except for the required alignment. */
tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_T1,
@@ -994,8 +946,11 @@ static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
/* Find a base address that can load both tlb comparator and addend. */
tlb_ofs = offsetof(CPUArchState, tlb_table[mem_index][0]);
- if (!check_fit_tl(tlb_ofs + sizeof(CPUTLBEntry), 13)) {
- tcg_out_addi(s, r1, tlb_ofs & ~0x3ff);
+ if (!check_fit_ptr(tlb_ofs + sizeof(CPUTLBEntry), 13)) {
+ if (tlb_ofs & ~0x3ff) {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, tlb_ofs & ~0x3ff);
+ tcg_out_arith(s, r1, r1, TCG_REG_T1, ARITH_ADD);
+ }
tlb_ofs &= 0x3ff;
}
@@ -1007,11 +962,11 @@ static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
tcg_out_cmp(s, r0, r2, 0);
/* If the guest address must be zero-extended, do so now. */
- if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) {
- tcg_out_arithi(s, r0, addrlo, 0, SHIFT_SRL);
+ if (SPARC64 && TARGET_LONG_BITS == 32) {
+ tcg_out_arithi(s, r0, addr, 0, SHIFT_SRL);
return r0;
}
- return addrlo;
+ return addr;
}
#endif /* CONFIG_SOFTMMU */
@@ -1044,78 +999,37 @@ static const int qemu_st_opc[16] = {
[MO_LEQ] = STX_LE,
};
-static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
+static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
+ TCGMemOp memop, int memi, bool is_64)
{
- TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused));
- TCGMemOp memop, s_bits;
-#if defined(CONFIG_SOFTMMU)
+#ifdef CONFIG_SOFTMMU
+ TCGMemOp s_bits = memop & MO_SIZE;
TCGReg addrz, param;
uintptr_t func;
- int memi;
- uint32_t *label_ptr[2];
-#endif
-
- datalo = *args++;
- datahi = (TCG_TARGET_REG_BITS == 32 && is64 ? *args++ : 0);
- addrlo = *args++;
- addrhi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS ? *args++ : 0);
- memop = *args++;
- s_bits = memop & MO_SIZE;
+ uint32_t *label_ptr;
-#if defined(CONFIG_SOFTMMU)
- memi = *args++;
- addrz = tcg_out_tlb_load(s, addrlo, addrhi, memi, s_bits,
+ addrz = tcg_out_tlb_load(s, addr, memi, s_bits,
offsetof(CPUTLBEntry, addr_read));
- if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
- int reg64;
-
- /* bne,pn %[xi]cc, label0 */
- label_ptr[0] = (uint32_t *)s->code_ptr;
- tcg_out_bpcc0(s, COND_NE, BPCC_PN
- | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0);
- tcg_out_nop(s);
-
- /* TLB Hit. */
- /* Load all 64-bits into an O/G register. */
- reg64 = (datalo < 16 ? datalo : TCG_REG_O0);
- tcg_out_ldst_rr(s, reg64, addrz, TCG_REG_O1, qemu_ld_opc[memop]);
+ /* The fast path is exactly one insn. Thus we can perform the
+ entire TLB Hit in the (annulled) delay slot of the branch
+ over the TLB Miss case. */
- /* Move the two 32-bit pieces into the destination registers. */
- tcg_out_arithi(s, datahi, reg64, 32, SHIFT_SRLX);
- if (reg64 != datalo) {
- tcg_out_mov(s, TCG_TYPE_I32, datalo, reg64);
- }
-
- /* b,a,pt label1 */
- label_ptr[1] = (uint32_t *)s->code_ptr;
- tcg_out_bpcc0(s, COND_A, BPCC_A | BPCC_PT, 0);
- } else {
- /* The fast path is exactly one insn. Thus we can perform the
- entire TLB Hit in the (annulled) delay slot of the branch
- over the TLB Miss case. */
-
- /* beq,a,pt %[xi]cc, label0 */
- label_ptr[0] = NULL;
- label_ptr[1] = (uint32_t *)s->code_ptr;
- tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT
- | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0);
- /* delay slot */
- tcg_out_ldst_rr(s, datalo, addrz, TCG_REG_O1, qemu_ld_opc[memop]);
- }
+ /* beq,a,pt %[xi]cc, label0 */
+ label_ptr = (uint32_t *)s->code_ptr;
+ tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT
+ | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0);
+ /* delay slot */
+ tcg_out_ldst_rr(s, data, addrz, TCG_REG_O1, qemu_ld_opc[memop]);
/* TLB Miss. */
- if (label_ptr[0]) {
- *label_ptr[0] |= INSN_OFF19((unsigned long)s->code_ptr -
- (unsigned long)label_ptr[0]);
- }
-
param = TCG_REG_O1;
- if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
- tcg_out_mov(s, TCG_TYPE_REG, param++, addrhi);
+ if (!SPARC64 && TARGET_LONG_BITS == 64) {
+ /* Skip the high-part; we'll perform the extract in the trampoline. */
+ param++;
}
- tcg_out_mov(s, TCG_TYPE_REG, param++, addrlo);
+ tcg_out_mov(s, TCG_TYPE_REG, param++, addr);
/* We use the helpers to extend SB and SW data, leaving the case
of SL needing explicit extending below. */
@@ -1129,81 +1043,54 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
/* delay slot */
tcg_out_movi(s, TCG_TYPE_I32, param, memi);
- switch (memop & ~MO_BSWAP) {
- case MO_SL:
- tcg_out_arithi(s, datalo, TCG_REG_O0, 0, SHIFT_SRA);
- break;
- case MO_Q:
- if (TCG_TARGET_REG_BITS == 32) {
- tcg_out_mov(s, TCG_TYPE_REG, datahi, TCG_REG_O0);
- tcg_out_mov(s, TCG_TYPE_REG, datalo, TCG_REG_O1);
- break;
+ /* Recall that all of the helpers return 64-bit results.
+ Which complicates things for sparcv8plus. */
+ if (SPARC64) {
+ /* We let the helper sign-extend SB and SW, but leave SL for here. */
+ if (is_64 && (memop & ~MO_BSWAP) == MO_SL) {
+ tcg_out_arithi(s, data, TCG_REG_O0, 0, SHIFT_SRA);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_REG, data, TCG_REG_O0);
+ }
+ } else {
+ if (s_bits == MO_64) {
+ tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O0, 32, SHIFT_SLLX);
+ tcg_out_arithi(s, TCG_REG_O1, TCG_REG_O1, 0, SHIFT_SRL);
+ tcg_out_arith(s, data, TCG_REG_O0, TCG_REG_O1, ARITH_OR);
+ } else if (is_64) {
+ /* Re-extend from 32-bit rather than reassembling when we
+ know the high register must be an extension. */
+ tcg_out_arithi(s, data, TCG_REG_O1, 0,
+ memop & MO_SIGN ? SHIFT_SRA : SHIFT_SRL);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, data, TCG_REG_O1);
}
- /* FALLTHRU */
- default:
- /* mov */
- tcg_out_mov(s, TCG_TYPE_REG, datalo, TCG_REG_O0);
- break;
}
- *label_ptr[1] |= INSN_OFF19((unsigned long)s->code_ptr -
- (unsigned long)label_ptr[1]);
+ *label_ptr |= INSN_OFF19((uintptr_t)s->code_ptr - (uintptr_t)label_ptr);
#else
- if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) {
- tcg_out_arithi(s, TCG_REG_T1, addrlo, 0, SHIFT_SRL);
- addrlo = TCG_REG_T1;
- }
- if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
- int reg64 = (datalo < 16 ? datalo : TCG_REG_O0);
-
- tcg_out_ldst_rr(s, reg64, addrlo,
- (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0),
- qemu_ld_opc[memop]);
-
- tcg_out_arithi(s, datahi, reg64, 32, SHIFT_SRLX);
- if (reg64 != datalo) {
- tcg_out_mov(s, TCG_TYPE_I32, datalo, reg64);
- }
- } else {
- tcg_out_ldst_rr(s, datalo, addrlo,
- (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0),
- qemu_ld_opc[memop]);
+ if (SPARC64 && TARGET_LONG_BITS == 32) {
+ tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL);
+ addr = TCG_REG_T1;
}
+ tcg_out_ldst_rr(s, data, addr,
+ (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0),
+ qemu_ld_opc[memop]);
#endif /* CONFIG_SOFTMMU */
}
-static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
+static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr,
+ TCGMemOp memop, int memi)
{
- TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused));
- TCGMemOp memop, s_bits;
-#if defined(CONFIG_SOFTMMU)
- TCGReg addrz, datafull, param;
+#ifdef CONFIG_SOFTMMU
+ TCGMemOp s_bits = memop & MO_SIZE;
+ TCGReg addrz, param;
uintptr_t func;
- int memi;
uint32_t *label_ptr;
-#endif
-
- datalo = *args++;
- datahi = (TCG_TARGET_REG_BITS == 32 && is64 ? *args++ : 0);
- addrlo = *args++;
- addrhi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS ? *args++ : 0);
- memop = *args++;
- s_bits = memop & MO_SIZE;
-#if defined(CONFIG_SOFTMMU)
- memi = *args++;
- addrz = tcg_out_tlb_load(s, addrlo, addrhi, memi, s_bits,
+ addrz = tcg_out_tlb_load(s, addr, memi, s_bits,
offsetof(CPUTLBEntry, addr_write));
- datafull = datalo;
- if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
- /* Reconstruct the full 64-bit value. */
- tcg_out_arithi(s, TCG_REG_T1, datalo, 0, SHIFT_SRL);
- tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX);
- tcg_out_arith(s, TCG_REG_O2, TCG_REG_T1, TCG_REG_O2, ARITH_OR);
- datafull = TCG_REG_O2;
- }
-
/* The fast path is exactly one insn. Thus we can perform the entire
TLB Hit in the (annulled) delay slot of the branch over TLB Miss. */
/* beq,a,pt %[xi]cc, label0 */
@@ -1211,19 +1098,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT
| (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0);
/* delay slot */
- tcg_out_ldst_rr(s, datafull, addrz, TCG_REG_O1, qemu_st_opc[memop]);
+ tcg_out_ldst_rr(s, data, addrz, TCG_REG_O1, qemu_st_opc[memop]);
/* TLB Miss. */
param = TCG_REG_O1;
- if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
- tcg_out_mov(s, TCG_TYPE_REG, param++, addrhi);
+ if (!SPARC64 && TARGET_LONG_BITS == 64) {
+ /* Skip the high-part; we'll perform the extract in the trampoline. */
+ param++;
}
- tcg_out_mov(s, TCG_TYPE_REG, param++, addrlo);
- if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
- tcg_out_mov(s, TCG_TYPE_REG, param++, datahi);
+ tcg_out_mov(s, TCG_TYPE_REG, param++, addr);
+ if (!SPARC64 && s_bits == MO_64) {
+ /* Skip the high-part; we'll perform the extract in the trampoline. */
+ param++;
}
- tcg_out_mov(s, TCG_TYPE_REG, param++, datalo);
+ tcg_out_mov(s, TCG_TYPE_REG, param++, data);
func = qemu_st_trampoline[memop];
assert(func != 0);
@@ -1231,106 +1120,100 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
/* delay slot */
tcg_out_movi(s, TCG_TYPE_REG, param, memi);
- *label_ptr |= INSN_OFF19((unsigned long)s->code_ptr -
- (unsigned long)label_ptr);
+ *label_ptr |= INSN_OFF19((uintptr_t)s->code_ptr - (uintptr_t)label_ptr);
#else
- if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) {
- tcg_out_arithi(s, TCG_REG_T1, addrlo, 0, SHIFT_SRL);
- addrlo = TCG_REG_T1;
- }
- if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
- tcg_out_arithi(s, TCG_REG_T1, datalo, 0, SHIFT_SRL);
- tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX);
- tcg_out_arith(s, TCG_REG_O2, TCG_REG_T1, TCG_REG_O2, ARITH_OR);
- datalo = TCG_REG_O2;
+ if (SPARC64 && TARGET_LONG_BITS == 32) {
+ tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL);
+ addr = TCG_REG_T1;
}
- tcg_out_ldst_rr(s, datalo, addrlo,
+ tcg_out_ldst_rr(s, data, addr,
(GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0),
qemu_st_opc[memop]);
#endif /* CONFIG_SOFTMMU */
}
-static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
- const int *const_args)
+static void tcg_out_op(TCGContext *s, TCGOpcode opc,
+ const TCGArg args[TCG_MAX_OP_ARGS],
+ const int const_args[TCG_MAX_OP_ARGS])
{
- int c;
+ TCGArg a0, a1, a2;
+ int c, c2;
+
+ /* Hoist the loads of the most common arguments. */
+ a0 = args[0];
+ a1 = args[1];
+ a2 = args[2];
+ c2 = const_args[2];
switch (opc) {
case INDEX_op_exit_tb:
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, args[0]);
- tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, JMPL);
- tcg_out32(s, RESTORE | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_G0) |
- INSN_RS2(TCG_REG_G0));
+ if (check_fit_ptr(a0, 13)) {
+ tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
+ tcg_out_movi_imm13(s, TCG_REG_O0, a0);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, a0 & ~0x3ff);
+ tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
+ tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O0, a0 & 0x3ff, ARITH_OR);
+ }
break;
case INDEX_op_goto_tb:
if (s->tb_jmp_offset) {
/* direct jump method */
uint32_t old_insn = *(uint32_t *)s->code_ptr;
- s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+ s->tb_jmp_offset[a0] = s->code_ptr - s->code_buf;
/* Make sure to preserve links during retranslation. */
tcg_out32(s, CALL | (old_insn & ~INSN_OP(-1)));
} else {
/* indirect jump method */
- tcg_out_ld_ptr(s, TCG_REG_T1, (uintptr_t)(s->tb_next + args[0]));
+ tcg_out_ld_ptr(s, TCG_REG_T1, (uintptr_t)(s->tb_next + a0));
tcg_out_arithi(s, TCG_REG_G0, TCG_REG_T1, 0, JMPL);
}
tcg_out_nop(s);
- s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+ s->tb_next_offset[a0] = s->code_ptr - s->code_buf;
break;
case INDEX_op_call:
if (const_args[0]) {
- tcg_out_calli(s, args[0]);
+ tcg_out_calli(s, a0);
} else {
- tcg_out_arithi(s, TCG_REG_O7, args[0], 0, JMPL);
+ tcg_out_arithi(s, TCG_REG_O7, a0, 0, JMPL);
}
/* delay slot */
tcg_out_nop(s);
break;
case INDEX_op_br:
- tcg_out_bpcc(s, COND_A, BPCC_PT, args[0]);
+ tcg_out_bpcc(s, COND_A, BPCC_PT, a0);
tcg_out_nop(s);
break;
- case INDEX_op_movi_i32:
- tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]);
- break;
-#if TCG_TARGET_REG_BITS == 64
#define OP_32_64(x) \
glue(glue(case INDEX_op_, x), _i32): \
glue(glue(case INDEX_op_, x), _i64)
-#else
-#define OP_32_64(x) \
- glue(glue(case INDEX_op_, x), _i32)
-#endif
+
OP_32_64(ld8u):
- tcg_out_ldst(s, args[0], args[1], args[2], LDUB);
+ tcg_out_ldst(s, a0, a1, a2, LDUB);
break;
OP_32_64(ld8s):
- tcg_out_ldst(s, args[0], args[1], args[2], LDSB);
+ tcg_out_ldst(s, a0, a1, a2, LDSB);
break;
OP_32_64(ld16u):
- tcg_out_ldst(s, args[0], args[1], args[2], LDUH);
+ tcg_out_ldst(s, a0, a1, a2, LDUH);
break;
OP_32_64(ld16s):
- tcg_out_ldst(s, args[0], args[1], args[2], LDSH);
+ tcg_out_ldst(s, a0, a1, a2, LDSH);
break;
case INDEX_op_ld_i32:
-#if TCG_TARGET_REG_BITS == 64
case INDEX_op_ld32u_i64:
-#endif
- tcg_out_ldst(s, args[0], args[1], args[2], LDUW);
+ tcg_out_ldst(s, a0, a1, a2, LDUW);
break;
OP_32_64(st8):
- tcg_out_ldst(s, args[0], args[1], args[2], STB);
+ tcg_out_ldst(s, a0, a1, a2, STB);
break;
OP_32_64(st16):
- tcg_out_ldst(s, args[0], args[1], args[2], STH);
+ tcg_out_ldst(s, a0, a1, a2, STH);
break;
case INDEX_op_st_i32:
-#if TCG_TARGET_REG_BITS == 64
case INDEX_op_st32_i64:
-#endif
- tcg_out_ldst(s, args[0], args[1], args[2], STW);
+ tcg_out_ldst(s, a0, a1, a2, STW);
break;
OP_32_64(add):
c = ARITH_ADD;
@@ -1357,7 +1240,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
c = SHIFT_SLL;
do_shift32:
/* Limit immediate shift count lest we create an illegal insn. */
- tcg_out_arithc(s, args[0], args[1], args[2] & 31, const_args[2], c);
+ tcg_out_arithc(s, a0, a1, a2 & 31, c2, c);
break;
case INDEX_op_shr_i32:
c = SHIFT_SRL;
@@ -1377,85 +1260,71 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
goto gen_arith1;
case INDEX_op_div_i32:
- tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 0);
+ tcg_out_div32(s, a0, a1, a2, c2, 0);
break;
case INDEX_op_divu_i32:
- tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 1);
+ tcg_out_div32(s, a0, a1, a2, c2, 1);
break;
case INDEX_op_brcond_i32:
- tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1],
- args[3]);
+ tcg_out_brcond_i32(s, a2, a0, a1, const_args[1], args[3]);
break;
case INDEX_op_setcond_i32:
- tcg_out_setcond_i32(s, args[3], args[0], args[1],
- args[2], const_args[2]);
+ tcg_out_setcond_i32(s, args[3], a0, a1, a2, c2);
break;
case INDEX_op_movcond_i32:
- tcg_out_movcond_i32(s, args[5], args[0], args[1],
- args[2], const_args[2], args[3], const_args[3]);
- break;
-
-#if TCG_TARGET_REG_BITS == 32
- case INDEX_op_brcond2_i32:
- tcg_out_brcond2_i32(s, args[4], args[0], args[1],
- args[2], const_args[2],
- args[3], const_args[3], args[5]);
+ tcg_out_movcond_i32(s, args[5], a0, a1, a2, c2, args[3], const_args[3]);
break;
- case INDEX_op_setcond2_i32:
- tcg_out_setcond2_i32(s, args[5], args[0], args[1], args[2],
- args[3], const_args[3],
- args[4], const_args[4]);
- break;
-#endif
case INDEX_op_add2_i32:
- tcg_out_addsub2(s, args[0], args[1], args[2], args[3],
- args[4], const_args[4], args[5], const_args[5],
- ARITH_ADDCC, ARITH_ADDX);
+ tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], const_args[4],
+ args[5], const_args[5], ARITH_ADDCC, ARITH_ADDX);
break;
case INDEX_op_sub2_i32:
- tcg_out_addsub2(s, args[0], args[1], args[2], args[3],
- args[4], const_args[4], args[5], const_args[5],
- ARITH_SUBCC, ARITH_SUBX);
+ tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], const_args[4],
+ args[5], const_args[5], ARITH_SUBCC, ARITH_SUBX);
break;
case INDEX_op_mulu2_i32:
- tcg_out_arithc(s, args[0], args[2], args[3], const_args[3],
- ARITH_UMUL);
- tcg_out_rdy(s, args[1]);
+ c = ARITH_UMUL;
+ goto do_mul2;
+ case INDEX_op_muls2_i32:
+ c = ARITH_SMUL;
+ do_mul2:
+ /* The 32-bit multiply insns produce a full 64-bit result. If the
+ destination register can hold it, we can avoid the slower RDY. */
+ tcg_out_arithc(s, a0, a2, args[3], const_args[3], c);
+ if (SPARC64 || a0 <= TCG_REG_O7) {
+ tcg_out_arithi(s, a1, a0, 32, SHIFT_SRLX);
+ } else {
+ tcg_out_rdy(s, a1);
+ }
break;
case INDEX_op_qemu_ld_i32:
- tcg_out_qemu_ld(s, args, 0);
+ tcg_out_qemu_ld(s, a0, a1, a2, args[3], false);
break;
case INDEX_op_qemu_ld_i64:
- tcg_out_qemu_ld(s, args, 1);
+ tcg_out_qemu_ld(s, a0, a1, a2, args[3], true);
break;
case INDEX_op_qemu_st_i32:
- tcg_out_qemu_st(s, args, 0);
- break;
case INDEX_op_qemu_st_i64:
- tcg_out_qemu_st(s, args, 1);
+ tcg_out_qemu_st(s, a0, a1, a2, args[3]);
break;
-#if TCG_TARGET_REG_BITS == 64
- case INDEX_op_movi_i64:
- tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
- break;
case INDEX_op_ld32s_i64:
- tcg_out_ldst(s, args[0], args[1], args[2], LDSW);
+ tcg_out_ldst(s, a0, a1, a2, LDSW);
break;
case INDEX_op_ld_i64:
- tcg_out_ldst(s, args[0], args[1], args[2], LDX);
+ tcg_out_ldst(s, a0, a1, a2, LDX);
break;
case INDEX_op_st_i64:
- tcg_out_ldst(s, args[0], args[1], args[2], STX);
+ tcg_out_ldst(s, a0, a1, a2, STX);
break;
case INDEX_op_shl_i64:
c = SHIFT_SLLX;
do_shift64:
/* Limit immediate shift count lest we create an illegal insn. */
- tcg_out_arithc(s, args[0], args[1], args[2] & 63, const_args[2], c);
+ tcg_out_arithc(s, a0, a1, a2 & 63, c2, c);
break;
case INDEX_op_shr_i64:
c = SHIFT_SRLX;
@@ -1473,35 +1342,44 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
c = ARITH_UDIVX;
goto gen_arith;
case INDEX_op_ext32s_i64:
- tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRA);
+ tcg_out_arithi(s, a0, a1, 0, SHIFT_SRA);
break;
case INDEX_op_ext32u_i64:
- tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRL);
+ tcg_out_arithi(s, a0, a1, 0, SHIFT_SRL);
+ break;
+ case INDEX_op_trunc_shr_i32:
+ if (a2 == 0) {
+ tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
+ } else {
+ tcg_out_arithi(s, a0, a1, a2, SHIFT_SRLX);
+ }
break;
case INDEX_op_brcond_i64:
- tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1],
- args[3]);
+ tcg_out_brcond_i64(s, a2, a0, a1, const_args[1], args[3]);
break;
case INDEX_op_setcond_i64:
- tcg_out_setcond_i64(s, args[3], args[0], args[1],
- args[2], const_args[2]);
+ tcg_out_setcond_i64(s, args[3], a0, a1, a2, c2);
break;
case INDEX_op_movcond_i64:
- tcg_out_movcond_i64(s, args[5], args[0], args[1],
- args[2], const_args[2], args[3], const_args[3]);
+ tcg_out_movcond_i64(s, args[5], a0, a1, a2, c2, args[3], const_args[3]);
break;
-#endif
+
gen_arith:
- tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c);
+ tcg_out_arithc(s, a0, a1, a2, c2, c);
break;
gen_arith1:
- tcg_out_arithc(s, args[0], TCG_REG_G0, args[1], const_args[1], c);
+ tcg_out_arithc(s, a0, TCG_REG_G0, a1, const_args[1], c);
break;
+ case INDEX_op_mov_i64:
+ case INDEX_op_mov_i32:
+ case INDEX_op_movi_i64:
+ case INDEX_op_movi_i32:
+ /* Always implemented with tcg_out_mov/i, never with tcg_out_op. */
default:
- fprintf(stderr, "unknown opcode 0x%x\n", opc);
+ /* Opcode not implemented. */
tcg_abort();
}
}
@@ -1545,72 +1423,55 @@ static const TCGTargetOpDef sparc_op_defs[] = {
{ INDEX_op_setcond_i32, { "r", "rZ", "rJ" } },
{ INDEX_op_movcond_i32, { "r", "rZ", "rJ", "rI", "0" } },
-#if TCG_TARGET_REG_BITS == 32
- { INDEX_op_brcond2_i32, { "rZ", "rZ", "rJ", "rJ" } },
- { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rJ", "rJ" } },
-#endif
-
{ INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } },
{ INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } },
{ INDEX_op_mulu2_i32, { "r", "r", "rZ", "rJ" } },
-
-#if TCG_TARGET_REG_BITS == 64
- { INDEX_op_mov_i64, { "r", "r" } },
- { INDEX_op_movi_i64, { "r" } },
- { INDEX_op_ld8u_i64, { "r", "r" } },
- { INDEX_op_ld8s_i64, { "r", "r" } },
- { INDEX_op_ld16u_i64, { "r", "r" } },
- { INDEX_op_ld16s_i64, { "r", "r" } },
- { INDEX_op_ld32u_i64, { "r", "r" } },
- { INDEX_op_ld32s_i64, { "r", "r" } },
- { INDEX_op_ld_i64, { "r", "r" } },
- { INDEX_op_st8_i64, { "rZ", "r" } },
- { INDEX_op_st16_i64, { "rZ", "r" } },
- { INDEX_op_st32_i64, { "rZ", "r" } },
- { INDEX_op_st_i64, { "rZ", "r" } },
-
- { INDEX_op_add_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_mul_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_div_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_divu_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_sub_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_and_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_andc_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_or_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_orc_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_xor_i64, { "r", "rZ", "rJ" } },
-
- { INDEX_op_shl_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_shr_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_sar_i64, { "r", "rZ", "rJ" } },
-
- { INDEX_op_neg_i64, { "r", "rJ" } },
- { INDEX_op_not_i64, { "r", "rJ" } },
-
- { INDEX_op_ext32s_i64, { "r", "r" } },
- { INDEX_op_ext32u_i64, { "r", "r" } },
-
- { INDEX_op_brcond_i64, { "rZ", "rJ" } },
- { INDEX_op_setcond_i64, { "r", "rZ", "rJ" } },
- { INDEX_op_movcond_i64, { "r", "rZ", "rJ", "rI", "0" } },
-#endif
-
-#if TCG_TARGET_REG_BITS == 64
- { INDEX_op_qemu_ld_i32, { "r", "L" } },
- { INDEX_op_qemu_ld_i64, { "r", "L" } },
- { INDEX_op_qemu_st_i32, { "L", "L" } },
- { INDEX_op_qemu_st_i64, { "L", "L" } },
-#elif TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
- { INDEX_op_qemu_ld_i32, { "r", "L" } },
- { INDEX_op_qemu_ld_i64, { "r", "r", "L" } },
- { INDEX_op_qemu_st_i32, { "L", "L" } },
- { INDEX_op_qemu_st_i64, { "L", "L", "L" } },
-#else
- { INDEX_op_qemu_ld_i32, { "r", "L", "L" } },
- { INDEX_op_qemu_ld_i64, { "L", "L", "L", "L" } },
- { INDEX_op_qemu_st_i32, { "L", "L", "L" } },
- { INDEX_op_qemu_st_i64, { "L", "L", "L", "L" } },
-#endif
+ { INDEX_op_muls2_i32, { "r", "r", "rZ", "rJ" } },
+
+ { INDEX_op_mov_i64, { "R", "R" } },
+ { INDEX_op_movi_i64, { "R" } },
+ { INDEX_op_ld8u_i64, { "R", "r" } },
+ { INDEX_op_ld8s_i64, { "R", "r" } },
+ { INDEX_op_ld16u_i64, { "R", "r" } },
+ { INDEX_op_ld16s_i64, { "R", "r" } },
+ { INDEX_op_ld32u_i64, { "R", "r" } },
+ { INDEX_op_ld32s_i64, { "R", "r" } },
+ { INDEX_op_ld_i64, { "R", "r" } },
+ { INDEX_op_st8_i64, { "RZ", "r" } },
+ { INDEX_op_st16_i64, { "RZ", "r" } },
+ { INDEX_op_st32_i64, { "RZ", "r" } },
+ { INDEX_op_st_i64, { "RZ", "r" } },
+
+ { INDEX_op_add_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_mul_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_div_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_divu_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_sub_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_and_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_andc_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_or_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_orc_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_xor_i64, { "R", "RZ", "RJ" } },
+
+ { INDEX_op_shl_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_shr_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_sar_i64, { "R", "RZ", "RJ" } },
+
+ { INDEX_op_neg_i64, { "R", "RJ" } },
+ { INDEX_op_not_i64, { "R", "RJ" } },
+
+ { INDEX_op_ext32s_i64, { "R", "r" } },
+ { INDEX_op_ext32u_i64, { "R", "r" } },
+ { INDEX_op_trunc_shr_i32, { "r", "R" } },
+
+ { INDEX_op_brcond_i64, { "RZ", "RJ" } },
+ { INDEX_op_setcond_i64, { "R", "RZ", "RJ" } },
+ { INDEX_op_movcond_i64, { "R", "RZ", "RJ", "RI", "0" } },
+
+ { INDEX_op_qemu_ld_i32, { "r", "A" } },
+ { INDEX_op_qemu_ld_i64, { "R", "A" } },
+ { INDEX_op_qemu_st_i32, { "sZ", "A" } },
+ { INDEX_op_qemu_st_i64, { "SZ", "A" } },
{ -1 },
};
@@ -1618,9 +1479,8 @@ static const TCGTargetOpDef sparc_op_defs[] = {
static void tcg_target_init(TCGContext *s)
{
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
-#if TCG_TARGET_REG_BITS == 64
- tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
-#endif
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, ALL_64);
+
tcg_regset_set32(tcg_target_call_clobber_regs, 0,
(1 << TCG_REG_G1) |
(1 << TCG_REG_G2) |
@@ -1650,7 +1510,7 @@ static void tcg_target_init(TCGContext *s)
tcg_add_target_add_op_defs(sparc_op_defs);
}
-#if TCG_TARGET_REG_BITS == 64
+#if SPARC64
# define ELF_HOST_MACHINE EM_SPARCV9
#else
# define ELF_HOST_MACHINE EM_SPARC32PLUS
@@ -1660,7 +1520,7 @@ static void tcg_target_init(TCGContext *s)
typedef struct {
DebugFrameCIE cie;
DebugFrameFDEHeader fde;
- uint8_t fde_def_cfa[TCG_TARGET_REG_BITS == 64 ? 4 : 2];
+ uint8_t fde_def_cfa[SPARC64 ? 4 : 2];
uint8_t fde_win_save;
uint8_t fde_ret_save[3];
} DebugFrame;
@@ -1677,7 +1537,7 @@ static DebugFrame debug_frame = {
.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
.fde_def_cfa = {
-#if TCG_TARGET_REG_BITS == 64
+#if SPARC64
12, 30, /* DW_CFA_def_cfa i6, 2047 */
(2047 & 0x7f) | 0x80, (2047 >> 7)
#else
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 4519c64..3a903db 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -24,13 +24,7 @@
#ifndef TCG_TARGET_SPARC
#define TCG_TARGET_SPARC 1
-#if UINTPTR_MAX == UINT32_MAX
-# define TCG_TARGET_REG_BITS 32
-#elif UINTPTR_MAX == UINT64_MAX
-# define TCG_TARGET_REG_BITS 64
-#else
-# error Unknown pointer size for tcg target
-#endif
+#define TCG_TARGET_REG_BITS 64
#define TCG_TARGET_NB_REGS 32
@@ -76,7 +70,7 @@ typedef enum {
/* used for function call generation */
#define TCG_REG_CALL_STACK TCG_REG_O6
-#if TCG_TARGET_REG_BITS == 64
+#ifdef __arch64__
#define TCG_TARGET_STACK_BIAS 2047
#define TCG_TARGET_STACK_ALIGN 16
#define TCG_TARGET_CALL_STACK_OFFSET (128 + 6*8 + TCG_TARGET_STACK_BIAS)
@@ -86,7 +80,7 @@ typedef enum {
#define TCG_TARGET_CALL_STACK_OFFSET (64 + 4 + 6*4)
#endif
-#if TCG_TARGET_REG_BITS == 64
+#ifdef __arch64__
#define TCG_TARGET_EXTEND_ARGS 1
#endif
@@ -112,11 +106,11 @@ typedef enum {
#define TCG_TARGET_HAS_add2_i32 1
#define TCG_TARGET_HAS_sub2_i32 1
#define TCG_TARGET_HAS_mulu2_i32 1
-#define TCG_TARGET_HAS_muls2_i32 0
+#define TCG_TARGET_HAS_muls2_i32 1
#define TCG_TARGET_HAS_muluh_i32 0
#define TCG_TARGET_HAS_mulsh_i32 0
-#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_trunc_shr_i32 1
#define TCG_TARGET_HAS_div_i64 1
#define TCG_TARGET_HAS_rem_i64 0
#define TCG_TARGET_HAS_rot_i64 0
@@ -144,7 +138,6 @@ typedef enum {
#define TCG_TARGET_HAS_muls2_i64 0
#define TCG_TARGET_HAS_muluh_i64 0
#define TCG_TARGET_HAS_mulsh_i64 0
-#endif
#define TCG_TARGET_HAS_new_ldst 1
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 8d4ff7d..6dbbb38 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -1624,9 +1624,20 @@ static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
}
-static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
+static inline void tcg_gen_trunc_shr_i64_i32(TCGv_i32 ret, TCGv_i64 arg,
+ unsigned int count)
{
- tcg_gen_mov_i32(ret, TCGV_LOW(arg));
+ tcg_debug_assert(count < 64);
+ if (count >= 32) {
+ tcg_gen_shri_i32(ret, TCGV_HIGH(arg), count - 32);
+ } else if (count == 0) {
+ tcg_gen_mov_i32(ret, TCGV_LOW(arg));
+ } else {
+ TCGv_i64 t = tcg_temp_new_i64();
+ tcg_gen_shri_i64(t, arg, count);
+ tcg_gen_mov_i32(ret, TCGV_LOW(t));
+ tcg_temp_free_i64(t);
+ }
}
static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
@@ -1727,11 +1738,21 @@ static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
}
}
-/* Note: we assume the target supports move between 32 and 64 bit
- registers. This will probably break MIPS64 targets. */
-static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
+static inline void tcg_gen_trunc_shr_i64_i32(TCGv_i32 ret, TCGv_i64 arg,
+ unsigned int count)
{
- tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg)));
+ tcg_debug_assert(count < 64);
+ if (TCG_TARGET_HAS_trunc_shr_i32) {
+ tcg_gen_op3i_i32(INDEX_op_trunc_shr_i32, ret,
+ MAKE_TCGV_I32(GET_TCGV_I64(arg)), count);
+ } else if (count == 0) {
+ tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg)));
+ } else {
+ TCGv_i64 t = tcg_temp_new_i64();
+ tcg_gen_shri_i64(t, arg, count);
+ tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(t)));
+ tcg_temp_free_i64(t);
+ }
}
/* Note: we assume the target supports move between 32 and 64 bit
@@ -2275,18 +2296,15 @@ static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low,
tcg_gen_deposit_i64(dest, low, high, 32, 32);
}
+static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
+{
+ tcg_gen_trunc_shr_i64_i32(ret, arg, 0);
+}
+
static inline void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg)
{
-#if TCG_TARGET_REG_BITS == 32
- tcg_gen_mov_i32(lo, TCGV_LOW(arg));
- tcg_gen_mov_i32(hi, TCGV_HIGH(arg));
-#else
- TCGv_i64 t0 = tcg_temp_new_i64();
- tcg_gen_trunc_i64_i32(lo, arg);
- tcg_gen_shri_i64(t0, arg, 32);
- tcg_gen_trunc_i64_i32(hi, t0);
- tcg_temp_free_i64(t0);
-#endif
+ tcg_gen_trunc_shr_i64_i32(lo, arg, 0);
+ tcg_gen_trunc_shr_i64_i32(hi, arg, 32);
}
static inline void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg)
@@ -2861,7 +2879,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
#define tcg_gen_muls2_tl tcg_gen_muls2_i32
#endif
-#if TCG_TARGET_REG_BITS == 32
+#if UINTPTR_MAX == UINT32_MAX
# define tcg_gen_ld_ptr(R, A, O) \
tcg_gen_ld_i32(TCGV_PTR_TO_NAT(R), (A), (O))
# define tcg_gen_discard_ptr(A) \
@@ -2883,4 +2901,4 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
tcg_gen_addi_i64(TCGV_PTR_TO_NAT(R), TCGV_PTR_TO_NAT(A), (B))
# define tcg_gen_ext_i32_ptr(R, A) \
tcg_gen_ext_i32_i64(TCGV_PTR_TO_NAT(R), (A))
-#endif /* TCG_TARGET_REG_BITS == 32 */
+#endif /* UINTPTR_MAX == UINT32_MAX */
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index d71707d..adb6ce1 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -147,6 +147,10 @@ DEF(rotl_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64))
DEF(rotr_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64))
DEF(deposit_i64, 1, 2, 2, IMPL64 | IMPL(TCG_TARGET_HAS_deposit_i64))
+DEF(trunc_shr_i32, 1, 1, 1,
+ IMPL(TCG_TARGET_HAS_trunc_shr_i32)
+ | (TCG_TARGET_REG_BITS == 32 ? TCG_OPF_NOT_PRESENT : 0))
+
DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | IMPL64)
DEF(ext8s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext8s_i64))
DEF(ext16s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext16s_i64))
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 21ce9fb..e71f7a0 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -664,7 +664,36 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
int nb_rets;
TCGArg *nparam;
-#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
+#if defined(__sparc__) && !defined(__arch64__) \
+ && !defined(CONFIG_TCG_INTERPRETER)
+ /* We have 64-bit values in one register, but need to pass as two
+ separate parameters. Split them. */
+ int orig_sizemask = sizemask;
+ int orig_nargs = nargs;
+ TCGv_i64 retl, reth;
+
+ TCGV_UNUSED_I64(retl);
+ TCGV_UNUSED_I64(reth);
+ if (sizemask != 0) {
+ TCGArg *split_args = __builtin_alloca(sizeof(TCGArg) * nargs * 2);
+ for (i = real_args = 0; i < nargs; ++i) {
+ int is_64bit = sizemask & (1 << (i+1)*2);
+ if (is_64bit) {
+ TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
+ TCGv_i32 h = tcg_temp_new_i32();
+ TCGv_i32 l = tcg_temp_new_i32();
+ tcg_gen_extr_i64_i32(l, h, orig);
+ split_args[real_args++] = GET_TCGV_I32(h);
+ split_args[real_args++] = GET_TCGV_I32(l);
+ } else {
+ split_args[real_args++] = args[i];
+ }
+ }
+ nargs = real_args;
+ args = split_args;
+ sizemask = 0;
+ }
+#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
for (i = 0; i < nargs; ++i) {
int is_64bit = sizemask & (1 << (i+1)*2);
int is_signed = sizemask & (2 << (i+1)*2);
@@ -684,8 +713,23 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
*s->gen_opc_ptr++ = INDEX_op_call;
nparam = s->gen_opparam_ptr++;
if (ret != TCG_CALL_DUMMY_ARG) {
-#if TCG_TARGET_REG_BITS < 64
- if (sizemask & 1) {
+#if defined(__sparc__) && !defined(__arch64__) \
+ && !defined(CONFIG_TCG_INTERPRETER)
+ if (orig_sizemask & 1) {
+ /* The 32-bit ABI is going to return the 64-bit value in
+ the %o0/%o1 register pair. Prepare for this by using
+ two return temporaries, and reassemble below. */
+ retl = tcg_temp_new_i64();
+ reth = tcg_temp_new_i64();
+ *s->gen_opparam_ptr++ = GET_TCGV_I64(reth);
+ *s->gen_opparam_ptr++ = GET_TCGV_I64(retl);
+ nb_rets = 2;
+ } else {
+ *s->gen_opparam_ptr++ = ret;
+ nb_rets = 1;
+ }
+#else
+ if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
#ifdef HOST_WORDS_BIGENDIAN
*s->gen_opparam_ptr++ = ret + 1;
*s->gen_opparam_ptr++ = ret;
@@ -694,12 +738,11 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
*s->gen_opparam_ptr++ = ret + 1;
#endif
nb_rets = 2;
- } else
-#endif
- {
+ } else {
*s->gen_opparam_ptr++ = ret;
nb_rets = 1;
}
+#endif
} else {
nb_rets = 0;
}
@@ -749,7 +792,29 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
/* total parameters, needed to go backward in the instruction stream */
*s->gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
-#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
+#if defined(__sparc__) && !defined(__arch64__) \
+ && !defined(CONFIG_TCG_INTERPRETER)
+ /* Free all of the parts we allocated above. */
+ for (i = real_args = 0; i < orig_nargs; ++i) {
+ int is_64bit = orig_sizemask & (1 << (i+1)*2);
+ if (is_64bit) {
+ TCGv_i32 h = MAKE_TCGV_I32(args[real_args++]);
+ TCGv_i32 l = MAKE_TCGV_I32(args[real_args++]);
+ tcg_temp_free_i32(h);
+ tcg_temp_free_i32(l);
+ } else {
+ real_args++;
+ }
+ }
+ if (orig_sizemask & 1) {
+ /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them.
+ Note that describing these as TCGv_i64 eliminates an unnecessary
+ zero-extension that tcg_gen_concat_i32_i64 would create. */
+ tcg_gen_concat32_i64(MAKE_TCGV_I64(ret), retl, reth);
+ tcg_temp_free_i64(retl);
+ tcg_temp_free_i64(reth);
+ }
+#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
for (i = 0; i < nargs; ++i) {
int is_64bit = sizemask & (1 << (i+1)*2);
if (!is_64bit) {
@@ -2411,6 +2476,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
ts = &s->temps[arg];
reg = tcg_target_call_oarg_regs[i];
assert(s->reg_to_temp[reg] == -1);
+
if (ts->fixed_reg) {
if (ts->reg != reg) {
tcg_out_mov(s, ts->type, ts->reg, reg);
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 0bb6677..a6a2d06 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -66,6 +66,7 @@ typedef uint64_t TCGRegSet;
#if TCG_TARGET_REG_BITS == 32
/* Turn some undef macros into false macros. */
+#define TCG_TARGET_HAS_trunc_shr_i32 0
#define TCG_TARGET_HAS_div_i64 0
#define TCG_TARGET_HAS_rem_i64 0
#define TCG_TARGET_HAS_div2_i64 0
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index f43492c..37719e8 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -82,6 +82,7 @@
#define TCG_TARGET_HAS_mulsh_i32 0
#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_trunc_shr_i32 0
#define TCG_TARGET_HAS_bswap16_i64 1
#define TCG_TARGET_HAS_bswap32_i64 1
#define TCG_TARGET_HAS_bswap64_i64 1
diff --git a/tests/Makefile b/tests/Makefile
index 88f7105..c6b6614 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -113,6 +113,10 @@ check-qtest-pci-y += tests/tpci200-test$(EXESUF)
gcov-files-pci-y += hw/ipack/tpci200.c
check-qtest-pci-y += $(check-qtest-ipack-y)
gcov-files-pci-y += $(gcov-files-ipack-y)
+check-qtest-pci-y += tests/display-vga-test$(EXESUF)
+gcov-files-pci-y += hw/display/vga.c
+gcov-files-pci-y += hw/display/cirrus_vga.c
+gcov-files-pci-y += hw/display/vga-pci.c
check-qtest-i386-y = tests/endianness-test$(EXESUF)
check-qtest-i386-y += tests/fdc-test$(EXESUF)
@@ -280,6 +284,7 @@ tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o
tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o
tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o
tests/tpci200-test$(EXESUF): tests/tpci200-test.o
+tests/display-vga-test$(EXESUF): tests/display-vga-test.o
tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
tests/qom-test$(EXESUF): tests/qom-test.o
tests/blockdev-test$(EXESUF): tests/blockdev-test.o $(libqos-pc-obj-y)
diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c
new file mode 100644
index 0000000..17f5910
--- /dev/null
+++ b/tests/display-vga-test.c
@@ -0,0 +1,52 @@
+/*
+ * QTest testcase for vga cards
+ *
+ * Copyright (c) 2014 Red Hat, Inc
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+static void pci_cirrus(void)
+{
+ qtest_start("-vga none -device cirrus-vga");
+ qtest_end();
+}
+
+static void pci_stdvga(void)
+{
+ qtest_start("-vga none -device VGA");
+ qtest_end();
+}
+
+static void pci_secondary(void)
+{
+ qtest_start("-vga none -device secondary-vga");
+ qtest_end();
+}
+
+static void pci_multihead(void)
+{
+ qtest_start("-vga none -device VGA -device secondary-vga");
+ qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/display/pci/cirrus", pci_cirrus);
+ qtest_add_func("/display/pci/stdvga", pci_stdvga);
+ qtest_add_func("/display/pci/secondary", pci_secondary);
+ qtest_add_func("/display/pci/multihead", pci_multihead);
+ ret = g_test_run();
+
+ return ret;
+}
diff --git a/ui/gtk.c b/ui/gtk.c
index 00fbbcc..9f5061a 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -93,13 +93,12 @@ static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
#define GDK_KEY_2 GDK_2
#define GDK_KEY_f GDK_f
#define GDK_KEY_g GDK_g
+#define GDK_KEY_q GDK_q
#define GDK_KEY_plus GDK_plus
#define GDK_KEY_minus GDK_minus
#endif
#define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK)
-#define IGNORE_MODIFIER_MASK \
- (GDK_MODIFIER_MASK & ~(GDK_LOCK_MASK | GDK_MOD2_MASK))
static const int modifier_keycode[] = {
/* shift, control, alt keys, meta keys, both left & right */
@@ -114,7 +113,6 @@ typedef struct VirtualConsole
GtkWidget *scrolled_window;
CharDriverState *chr;
#endif
- int fd;
} VirtualConsole;
typedef struct GtkDisplayState
@@ -489,24 +487,6 @@ static void gd_mouse_mode_change(Notifier *notify, void *data)
/** GTK Events **/
-static gboolean gd_window_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
-{
- GtkDisplayState *s = opaque;
- gboolean handled = FALSE;
-
- if (!gd_is_grab_active(s) ||
- (key->state & IGNORE_MODIFIER_MASK) == HOTKEY_MODIFIERS) {
- handled = gtk_window_activate_key(GTK_WINDOW(widget), key);
- }
- if (handled) {
- gtk_release_modifiers(s);
- } else {
- handled = gtk_window_propagate_key_event(GTK_WINDOW(widget), key);
- }
-
- return handled;
-}
-
static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
void *opaque)
{
@@ -1161,9 +1141,12 @@ static gboolean gd_focus_out_event(GtkWidget *widget,
static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
+#if defined(CONFIG_VTE)
VirtualConsole *vc = chr->opaque;
- return vc ? write(vc->fd, buf, len) : len;
+ vte_terminal_feed(VTE_TERMINAL(vc->terminal), (const char *)buf, len);
+#endif
+ return len;
}
static int nb_vcs;
@@ -1189,19 +1172,12 @@ void early_gtk_display_init(void)
}
#if defined(CONFIG_VTE)
-static gboolean gd_vc_in(GIOChannel *chan, GIOCondition cond, void *opaque)
+static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
+ gpointer user_data)
{
- VirtualConsole *vc = opaque;
- uint8_t buffer[1024];
- ssize_t len;
-
- len = read(vc->fd, buffer, sizeof(buffer));
- if (len <= 0) {
- return FALSE;
- }
-
- qemu_chr_be_write(vc->chr, buffer, len);
+ VirtualConsole *vc = user_data;
+ qemu_chr_be_write(vc->chr, (uint8_t *)text, (unsigned int)size);
return TRUE;
}
#endif
@@ -1213,13 +1189,8 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL
const char *label;
char buffer[32];
char path[32];
-#if VTE_CHECK_VERSION(0, 26, 0)
- VtePty *pty;
-#endif
- GIOChannel *chan;
GtkWidget *scrolled_window;
GtkAdjustment *vadjustment;
- int master_fd, slave_fd;
snprintf(buffer, sizeof(buffer), "vc%d", index);
snprintf(path, sizeof(path), "<QEMU>/View/VC%d", index);
@@ -1238,27 +1209,21 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL
gtk_accel_map_add_entry(path, GDK_KEY_2 + index, HOTKEY_MODIFIERS);
vc->terminal = vte_terminal_new();
-
- master_fd = qemu_openpty_raw(&slave_fd, NULL);
- g_assert(master_fd != -1);
-
-#if VTE_CHECK_VERSION(0, 26, 0)
- pty = vte_pty_new_foreign(master_fd, NULL);
- vte_terminal_set_pty_object(VTE_TERMINAL(vc->terminal), pty);
-#else
- vte_terminal_set_pty(VTE_TERMINAL(vc->terminal), master_fd);
-#endif
+ g_signal_connect(vc->terminal, "commit", G_CALLBACK(gd_vc_in), vc);
vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->terminal), -1);
+#if VTE_CHECK_VERSION(0, 28, 0) && GTK_CHECK_VERSION(3, 0, 0)
+ vadjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(vc->terminal));
+#else
vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->terminal));
+#endif
scrolled_window = gtk_scrolled_window_new(NULL, vadjustment);
gtk_container_add(GTK_CONTAINER(scrolled_window), vc->terminal);
vte_terminal_set_size(VTE_TERMINAL(vc->terminal), 80, 25);
- vc->fd = slave_fd;
vc->chr->opaque = vc;
vc->scrolled_window = scrolled_window;
@@ -1276,9 +1241,6 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL
vc->chr->init(vc->chr);
}
- chan = g_io_channel_unix_new(vc->fd);
- g_io_add_watch(chan, G_IO_IN, gd_vc_in, vc);
-
#endif /* CONFIG_VTE */
return group;
}
@@ -1290,8 +1252,6 @@ static void gd_connect_signals(GtkDisplayState *s)
g_signal_connect(s->show_tabs_item, "activate",
G_CALLBACK(gd_menu_show_tabs), s);
- g_signal_connect(s->window, "key-press-event",
- G_CALLBACK(gd_window_key_event), s);
g_signal_connect(s->window, "delete-event",
G_CALLBACK(gd_window_close), s);
@@ -1351,7 +1311,6 @@ static GtkWidget *gd_create_menu_machine(GtkDisplayState *s, GtkAccelGroup *acce
{
GtkWidget *machine_menu;
GtkWidget *separator;
- GtkStockItem item;
machine_menu = gtk_menu_new();
gtk_menu_set_accel_group(GTK_MENU(machine_menu), accel_group);
@@ -1362,20 +1321,20 @@ static GtkWidget *gd_create_menu_machine(GtkDisplayState *s, GtkAccelGroup *acce
separator = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), separator);
- s->reset_item = gtk_image_menu_item_new_with_mnemonic(_("_Reset"));
+ s->reset_item = gtk_menu_item_new_with_mnemonic(_("_Reset"));
gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), s->reset_item);
- s->powerdown_item = gtk_image_menu_item_new_with_mnemonic(_("Power _Down"));
+ s->powerdown_item = gtk_menu_item_new_with_mnemonic(_("Power _Down"));
gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), s->powerdown_item);
separator = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), separator);
- s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
- gtk_stock_lookup(GTK_STOCK_QUIT, &item);
+ s->quit_item = gtk_menu_item_new_with_mnemonic(_("_Quit"));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
"<QEMU>/Machine/Quit");
- gtk_accel_map_add_entry("<QEMU>/Machine/Quit", item.keyval, item.modifier);
+ gtk_accel_map_add_entry("<QEMU>/Machine/Quit",
+ GDK_KEY_q, HOTKEY_MODIFIERS);
gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), s->quit_item);
return machine_menu;
@@ -1391,8 +1350,7 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_g
view_menu = gtk_menu_new();
gtk_menu_set_accel_group(GTK_MENU(view_menu), accel_group);
- s->full_screen_item =
- gtk_image_menu_item_new_from_stock(GTK_STOCK_FULLSCREEN, NULL);
+ s->full_screen_item = gtk_menu_item_new_with_mnemonic(_("_Fullscreen"));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item),
"<QEMU>/View/Full Screen");
gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f,
@@ -1402,21 +1360,21 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_g
separator = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), separator);
- s->zoom_in_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_IN, NULL);
+ s->zoom_in_item = gtk_menu_item_new_with_mnemonic(_("Zoom _In"));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item),
"<QEMU>/View/Zoom In");
gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus,
HOTKEY_MODIFIERS);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_in_item);
- s->zoom_out_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_OUT, NULL);
+ s->zoom_out_item = gtk_menu_item_new_with_mnemonic(_("Zoom _Out"));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item),
"<QEMU>/View/Zoom Out");
gtk_accel_map_add_entry("<QEMU>/View/Zoom Out", GDK_KEY_minus,
HOTKEY_MODIFIERS);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_out_item);
- s->zoom_fixed_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_100, NULL);
+ s->zoom_fixed_item = gtk_menu_item_new_with_mnemonic(_("Best _Fit"));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item),
"<QEMU>/View/Zoom Fixed");
gtk_accel_map_add_entry("<QEMU>/View/Zoom Fixed", GDK_KEY_0,
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 7506e2e..361de61 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -359,16 +359,12 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data)
}
static void sdl_send_mouse_event(struct sdl2_state *scon, int dx, int dy,
- int dz, int x, int y, int state)
+ int x, int y, int state)
{
static uint32_t bmap[INPUT_BUTTON_MAX] = {
[INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT),
[INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE),
[INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT),
-#if 0
- [INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP),
- [INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN),
-#endif
};
static uint32_t prev_state;
@@ -566,7 +562,7 @@ static void handle_mousemotion(SDL_Event *ev)
}
}
if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
- sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, 0,
+ sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel,
ev->motion.x, ev->motion.y, ev->motion.state);
}
}
@@ -576,7 +572,6 @@ static void handle_mousebutton(SDL_Event *ev)
int buttonstate = SDL_GetMouseState(NULL, NULL);
SDL_MouseButtonEvent *bev;
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
- int dz;
bev = &ev->button;
if (!gui_grab && !qemu_input_is_absolute()) {
@@ -585,25 +580,35 @@ static void handle_mousebutton(SDL_Event *ev)
sdl_grab_start(scon);
}
} else {
- dz = 0;
if (ev->type == SDL_MOUSEBUTTONDOWN) {
buttonstate |= SDL_BUTTON(bev->button);
} else {
buttonstate &= ~SDL_BUTTON(bev->button);
}
-#ifdef SDL_BUTTON_WHEELUP
- if (bev->button == SDL_BUTTON_WHEELUP &&
- ev->type == SDL_MOUSEBUTTONDOWN) {
- dz = -1;
- } else if (bev->button == SDL_BUTTON_WHEELDOWN &&
- ev->type == SDL_MOUSEBUTTONDOWN) {
- dz = 1;
- }
-#endif
- sdl_send_mouse_event(scon, 0, 0, dz, bev->x, bev->y, buttonstate);
+ sdl_send_mouse_event(scon, 0, 0, bev->x, bev->y, buttonstate);
}
}
+static void handle_mousewheel(SDL_Event *ev)
+{
+ struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
+ SDL_MouseWheelEvent *wev = &ev->wheel;
+ InputButton btn;
+
+ if (wev->y > 0) {
+ btn = INPUT_BUTTON_WHEEL_UP;
+ } else if (wev->y < 0) {
+ btn = INPUT_BUTTON_WHEEL_DOWN;
+ } else {
+ return;
+ }
+
+ qemu_input_queue_btn(scon->dcl.con, btn, true);
+ qemu_input_event_sync();
+ qemu_input_queue_btn(scon->dcl.con, btn, false);
+ qemu_input_event_sync();
+}
+
static void handle_windowevent(DisplayChangeListener *dcl, SDL_Event *ev)
{
int w, h;
@@ -612,6 +617,13 @@ static void handle_windowevent(DisplayChangeListener *dcl, SDL_Event *ev)
switch (ev->window.event) {
case SDL_WINDOWEVENT_RESIZED:
sdl_scale(scon, ev->window.data1, ev->window.data2);
+ {
+ QemuUIInfo info;
+ memset(&info, 0, sizeof(info));
+ info.width = ev->window.data1;
+ info.height = ev->window.data2;
+ dpy_set_ui_info(scon->dcl.con, &info);
+ }
graphic_hw_invalidate(scon->dcl.con);
graphic_hw_update(scon->dcl.con);
break;
@@ -678,6 +690,9 @@ static void sdl_refresh(DisplayChangeListener *dcl)
case SDL_MOUSEBUTTONUP:
handle_mousebutton(ev);
break;
+ case SDL_MOUSEWHEEL:
+ handle_mousewheel(ev);
+ break;
case SDL_WINDOWEVENT:
handle_windowevent(dcl, ev);
break;