diff options
35 files changed, 741 insertions, 657 deletions
@@ -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)¶ms; 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); } @@ -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)) @@ -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); @@ -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; +} @@ -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, @@ -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; |