Skip to contentSkip to conversation

dmult & dmultu emulation

PATCH In review Aurelien Jarno 4 participants 8 messages May 15, 2007 – May 16, 2007 1 message not in the archive Kbuild

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 dmult & dmultu emulation

Hi,

The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.

On x86_64, it uses the mul/imul instruction, an equivalent C code (but much slower) is provided for other architectures.

Cheers,
Aurelien

Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v retrieving revision 1.45

op_helper.c +39 -6
diff -u -d -p -r1.45 op_helper.c
@@ -230,16 +230,49 @@ void do_div (void)
 #ifdef TARGET_MIPS64
 void do_dmult (void)
 {
-    env->LO = (int64_t)T0 * (int64_t)T1;
-    /* XXX */
-    env->HI = (env->LO | (1ULL << 63)) ? ~0ULL : 0ULL;
+#if defined(__x86_64__)
+    __asm__ ("imul %0\n\t"
+             : "=d" (env->HI), "=a" (env->LO)
+             : "a" (T0), "0" (T1)
+             );
+#else
+    int64_t ph;
+    uint64_t pm1, pm2, pl;
+
+    pl = (uint64_t)((uint32_t)T0) * (uint64_t)((uint32_t)T1);
+    pm1 = ((int64_t)T0 >> 32) * (uint32_t)T1;
+    pm2 = (uint32_t)T0 * ((int64_t)T1 >> 32);
+    ph = ((int64_t)T0 >> 32) * ((int64_t)T1 >> 32);
+
+    ph += ((int64_t)pm1) >> 32;	
+    pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32);
+
+    env->HI = ph + ((int64_t)pm1) >> 32;
+    env->LO = (pm1 << 32) + (uint32_t)pl;
+#endif
 }
 
 void do_dmultu (void)
 {
-    env->LO = T0 * T1;
-    /* XXX */
-    env->HI = 0;
+#if defined(__x86_64__)
+    __asm__ ("mul %0\n\t"
+             : "=d" (env->HI), "=a" (env->LO)
+             : "a" (T0), "0" (T1)
+            );
+#else
+    uint64_t ph, pm1, pm2, pl;
+
+    pl = (uint64_t)((uint32_t)T0) * (uint64_t)((uint32_t)T1);
+    pm1 = (T0 >> 32) * (uint32_t)T1;
+    pm2 = (uint32_t)T0 * (T1 >> 32);
+    ph = (T0 >> 32) * (T1 >> 32);
+
+    ph += pm1 >> 32;
+    pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32);
+
+    env->HI = ph + (pm1 >> 32);
+    env->LO = (pm1 << 32) + (uint32_t)pl;
+#endif
 }
 
 void do_ddiv (void)
Signature · 4 lines
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   [email protected]         | [email protected]
   `-    people.debian.org/~aurel32 | www.aurel32.net
#1 lore raw
Quoted 2 lines

The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.

Can we share the implementation between targets please. We already have an implementation of mul64 in target-i386/helper.c.

I've no real preference which implementation we use, I just don't want there to be several of them.

Paul

#2 lore raw
Quoted 8 lines · Paul Brook
Quoted 2 lines

The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.

Can we share the implementation between targets please. We already have an implementation of mul64 in target-i386/helper.c.

I've no real preference which implementation we use, I just don't want there to be several of them.

Ok, please find an updated patch below. The multiplications functions are in mul64.c and are now shared by the i386 and mips targets.

Bye,
Aurelien

Index: Makefile.target
===================================================================
RCS file: /sources/qemu/qemu/Makefile.target,v
retrieving revision 1.169

Makefile.target +1 -0
diff -u -d -p -r1.169 Makefile.target
@@ -365,6 +365,7 @@ endif
 # must use static linking to avoid leaving stuff in virtual address space
 VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.o
 VL_OBJS+=cutils.o
+VL_OBJS+=mul64.o
 VL_OBJS+=block.o block-raw.o
 VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o
 VL_OBJS+=irq.o

Index: exec-all.h
===================================================================
RCS file: /sources/qemu/qemu/exec-all.h,v
retrieving revision 1.54

exec-all.h +3 -0
diff -u -d -p -r1.54 exec-all.h
@@ -78,6 +78,9 @@ void optimize_flags_init(void);
 extern FILE *logfile;
 extern int loglevel;
 
+void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b);
+void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
+
 int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
 int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
 void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);

Index: target-i386/helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper.c,v retrieving revision 1.80

helper.c +3 -47

74 lines not on this page · raw message

Index: target-mips/exec.h
===================================================================
RCS file: /sources/qemu/qemu/target-mips/exec.h,v
retrieving revision 1.26

exec.h +0 -2
diff -u -d -p -r1.26 exec.h
@@ -97,8 +97,6 @@ void do_ddiv (void);
 #if TARGET_LONG_BITS > HOST_LONG_BITS
 void do_ddivu (void);
 #endif
-void do_dmult (void);
-void do_dmultu (void);
 #endif
 void do_mfc0_random(void);
 void do_mfc0_count(void);

Index: target-mips/op.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op.c,v
retrieving revision 1.54

op.c +2 -2
diff -u -d -p -r1.54 op.c
@@ -874,13 +874,13 @@ void op_msubu (void)
 #ifdef TARGET_MIPS64
 void op_dmult (void)
 {
-    CALL_FROM_TB0(do_dmult);
+    CALL_FROM_TB4(muls64, &(env->HI), &(env->LO), T0, T1);
     RETURN();
 }
 
 void op_dmultu (void)
 {
-    CALL_FROM_TB0(do_dmultu);
+    CALL_FROM_TB4(mulu64, &(env->HI), &(env->LO), T0, T1);
     RETURN();
 }
 #endif

Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v retrieving revision 1.45

op_helper.c +0 -14
diff -u -d -p -r1.45 op_helper.c
@@ -228,20 +228,6 @@ void do_div (void)
 #endif
 
 #ifdef TARGET_MIPS64
-void do_dmult (void)
-{
-    env->LO = (int64_t)T0 * (int64_t)T1;
-    /* XXX */
-    env->HI = (env->LO | (1ULL << 63)) ? ~0ULL : 0ULL;
-}
-
-void do_dmultu (void)
-{
-    env->LO = T0 * T1;
-    /* XXX */
-    env->HI = 0;
-}
-
 void do_ddiv (void)
 {
     if (T1 != 0) {
mul64.c +77 -0

77 lines not on this page · raw message

Signature · 4 lines
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   [email protected]         | [email protected]
   `-    people.debian.org/~aurel32 | www.aurel32.net
#3 lore raw

Would this patch work with other 64-bit processors, or is it x86-64-only? I'm mainly thinking about 64-bit PowerPCs, but I don't know if PowerPCs uses the same method.

A message that is not in the archive (sent off-list or not yet received): [email protected]

#5 lore raw
Quoted 3 lines · C.W. Betts

Would this patch work with other 64-bit processors, or is it x86-64-only? I'm mainly thinking about 64-bit PowerPCs, but I don't know if PowerPCs uses the same method.

You may have missed the x86-64 specific assembly code in there.

Thiemo

#6 lore raw
In reply to a message not in the archive
Quoted 3 lines · C.W. Betts

Would this patch work with other 64-bit processors, or is it x86-64-only? I'm mainly thinking about 64-bit PowerPCs, but I don't know if PowerPCs uses the same method.

This patch works on all hosts CPU using the C version, but it can use an assembly version for x86_64. If there is the equivalent assembly instruction for 64-bit PowerPCs, it is possible to add it to this file.

Signature · 4 lines
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   [email protected]         | [email protected]
   `-    people.debian.org/~aurel32 | www.aurel32.net
#7 lore raw
In reply to Aurelien Jarno
Quoted 4 lines · Aurelien Jarno
Quoted 3 lines · Paul Brook
Quoted 2 lines

The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.

Quoted 9 lines
Quoted 5 lines

Can we share the implementation between targets please. We already have an implementation of mul64 in target-i386/helper.c.

I've no real preference which implementation we use, I just don't want there to be several of them.

Ok, please find an updated patch below. The multiplications functions are in mul64.c and are now shared by the i386 and mips targets.

03:40 < pbrook> aurel32: I think you've got a sign mismatch in your target-i386/helper.c patch. You've replaced imul64 with mulu64.

I confirm I have made a mistake here, please find an updated patch below.

Bye,
Aurelien

Index: Makefile.target
===================================================================
RCS file: /sources/qemu/qemu/Makefile.target,v
retrieving revision 1.169

Makefile.target +1 -0
diff -u -d -p -r1.169 Makefile.target
@@ -365,6 +365,7 @@ endif
 # must use static linking to avoid leaving stuff in virtual address space
 VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.o
 VL_OBJS+=cutils.o
+VL_OBJS+=mul64.o
 VL_OBJS+=block.o block-raw.o
 VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o
 VL_OBJS+=irq.o

Index: exec-all.h
===================================================================
RCS file: /sources/qemu/qemu/exec-all.h,v
retrieving revision 1.54

exec-all.h +3 -0
diff -u -d -p -r1.54 exec-all.h
@@ -78,6 +78,9 @@ void optimize_flags_init(void);
 extern FILE *logfile;
 extern int loglevel;
 
+void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b);
+void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
+
 int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
 int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
 void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);

Index: target-i386/helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper.c,v retrieving revision 1.80

helper.c +3 -47

74 lines not on this page · raw message

Index: target-mips/exec.h
===================================================================
RCS file: /sources/qemu/qemu/target-mips/exec.h,v
retrieving revision 1.26

exec.h +0 -2
diff -u -d -p -r1.26 exec.h
@@ -97,8 +97,6 @@ void do_ddiv (void);
 #if TARGET_LONG_BITS > HOST_LONG_BITS
 void do_ddivu (void);
 #endif
-void do_dmult (void);
-void do_dmultu (void);
 #endif
 void do_mfc0_random(void);
 void do_mfc0_count(void);

Index: target-mips/op.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op.c,v
retrieving revision 1.54

op.c +2 -2
diff -u -d -p -r1.54 op.c
@@ -874,13 +874,13 @@ void op_msubu (void)
 #ifdef TARGET_MIPS64
 void op_dmult (void)
 {
-    CALL_FROM_TB0(do_dmult);
+    CALL_FROM_TB4(muls64, &(env->HI), &(env->LO), T0, T1);
     RETURN();
 }
 
 void op_dmultu (void)
 {
-    CALL_FROM_TB0(do_dmultu);
+    CALL_FROM_TB4(mulu64, &(env->HI), &(env->LO), T0, T1);
     RETURN();
 }
 #endif

Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v retrieving revision 1.45

op_helper.c +0 -14
diff -u -d -p -r1.45 op_helper.c
@@ -228,20 +228,6 @@ void do_div (void)
 #endif
 
 #ifdef TARGET_MIPS64
-void do_dmult (void)
-{
-    env->LO = (int64_t)T0 * (int64_t)T1;
-    /* XXX */
-    env->HI = (env->LO | (1ULL << 63)) ? ~0ULL : 0ULL;
-}
-
-void do_dmultu (void)
-{
-    env->LO = T0 * T1;
-    /* XXX */
-    env->HI = 0;
-}
-
 void do_ddiv (void)
 {
     if (T1 != 0) {
mul64.c +78 -0

78 lines not on this page · raw message

Signature · 4 lines
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   [email protected]         | [email protected]
   `-    people.debian.org/~aurel32 | www.aurel32.net
#8 lore raw
Quoted 11 lines · Aurelien Jarno
Quoted 10 lines · Aurelien Jarno
Quoted 8 lines · Paul Brook
Quoted 2 lines

The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.

Can we share the implementation between targets please. We already have an implementation of mul64 in target-i386/helper.c.

I've no real preference which implementation we use, I just don't want there to be several of them.

Quoted 8 lines
Quoted 3 lines

Ok, please find an updated patch below. The multiplications functions are in mul64.c and are now shared by the i386 and mips targets.

03:40 < pbrook> aurel32: I think you've got a sign mismatch in your target-i386/helper.c patch. You've replaced imul64 with mulu64.

I confirm I have made a mistake here, please find an updated patch below.

I moved the file to host-utils.c, there may be more such functions needed some day.

Thiemo